Current Path: > home > codekrsu > > cuddlebuds.lk > wp-content > plugins > woocommerce > includes
Operation : Linux premium131.web-hosting.com 4.18.0-553.44.1.lve.el8.x86_64 #1 SMP Thu Mar 13 14:29:12 UTC 2025 x86_64 Software : Apache Server IP : 162.0.232.56 | Your IP: 216.73.216.111 Domains : 1034 Domain(s) Permission : [ 0755 ]
Name | Type | Size | Last Modified | Actions |
---|---|---|---|---|
abstracts | Directory | - | - | |
admin | Directory | - | - | |
blocks | Directory | - | - | |
cli | Directory | - | - | |
customizer | Directory | - | - | |
data-stores | Directory | - | - | |
emails | Directory | - | - | |
export | Directory | - | - | |
gateways | Directory | - | - | |
import | Directory | - | - | |
integrations | Directory | - | - | |
interfaces | Directory | - | - | |
legacy | Directory | - | - | |
libraries | Directory | - | - | |
log-handlers | Directory | - | - | |
payment-tokens | Directory | - | - | |
product-usage | Directory | - | - | |
queue | Directory | - | - | |
react-admin | Directory | - | - | |
rest-api | Directory | - | - | |
shipping | Directory | - | - | |
shortcodes | Directory | - | - | |
theme-support | Directory | - | - | |
tracks | Directory | - | - | |
traits | Directory | - | - | |
walkers | Directory | - | - | |
wccom-site | Directory | - | - | |
widgets | Directory | - | - | |
class-wc-ajax.php | File | 122567 bytes | June 23 2025 19:46:28. | |
class-wc-auth.php | File | 12995 bytes | July 30 2024 19:31:16. | |
class-wc-autoloader.php | File | 3401 bytes | September 23 2024 20:44:04. | |
class-wc-background-emailer.php | File | 4685 bytes | August 20 2020 23:18:50. | |
class-wc-background-updater.php | File | 3535 bytes | August 20 2020 23:18:50. | |
class-wc-brands-brand-settings-manager.php | File | 1826 bytes | September 23 2024 20:44:04. | |
class-wc-brands-coupons.php | File | 7059 bytes | January 21 2025 18:53:44. | |
class-wc-brands.php | File | 34095 bytes | July 07 2025 13:23:42. | |
class-wc-breadcrumb.php | File | 9722 bytes | October 21 2020 03:38:50. | |
class-wc-cache-helper.php | File | 11438 bytes | August 27 2024 23:04:44. | |
class-wc-cart-fees.php | File | 3448 bytes | September 26 2023 21:42:36. | |
class-wc-cart-session.php | File | 20140 bytes | June 23 2025 19:46:28. | |
class-wc-cart-totals.php | File | 29166 bytes | July 07 2025 13:23:42. | |
class-wc-cart.php | File | 72605 bytes | June 30 2025 17:49:22. | |
class-wc-checkout.php | File | 51349 bytes | May 12 2025 21:07:28. | |
class-wc-cli.php | File | 2935 bytes | May 12 2025 21:07:28. | |
class-wc-comments.php | File | 23066 bytes | June 23 2025 19:46:28. | |
class-wc-countries.php | File | 50342 bytes | May 12 2025 21:07:28. | |
class-wc-coupon.php | File | 40825 bytes | June 23 2025 19:46:28. | |
class-wc-customer-download-log.php | File | 3452 bytes | August 20 2020 23:18:50. | |
class-wc-customer-download.php | File | 10587 bytes | July 30 2024 19:31:16. | |
class-wc-customer.php | File | 33300 bytes | June 23 2025 19:46:28. | |
class-wc-data-exception.php | File | 1321 bytes | May 23 2018 19:30:10. | |
class-wc-data-store.php | File | 6752 bytes | October 19 2022 00:34:38. | |
class-wc-datetime.php | File | 2310 bytes | April 20 2022 06:50:54. | |
class-wc-deprecated-action-hooks.php | File | 6746 bytes | February 27 2024 18:59:46. | |
class-wc-deprecated-filter-hooks.php | File | 7518 bytes | February 22 2023 07:17:34. | |
class-wc-discounts.php | File | 37476 bytes | June 23 2025 19:46:28. | |
class-wc-download-handler.php | File | 29053 bytes | December 18 2024 22:19:16. | |
class-wc-emails.php | File | 34457 bytes | June 23 2025 19:46:28. | |
class-wc-embed.php | File | 4342 bytes | January 21 2025 18:53:44. | |
class-wc-form-handler.php | File | 46932 bytes | June 23 2025 19:46:28. | |
class-wc-frontend-scripts.php | File | 28511 bytes | May 12 2025 21:07:28. | |
class-wc-geo-ip.php | File | 31139 bytes | June 23 2025 19:46:28. | |
class-wc-geolite-integration.php | File | 2036 bytes | January 16 2020 06:10:02. | |
class-wc-geolocation.php | File | 11594 bytes | May 12 2025 21:07:28. | |
class-wc-https.php | File | 4439 bytes | June 20 2023 23:45:50. | |
class-wc-install.php | File | 109669 bytes | June 23 2025 19:46:28. | |
class-wc-integrations.php | File | 1308 bytes | August 20 2020 23:18:50. | |
class-wc-log-levels.php | File | 3992 bytes | January 30 2024 23:24:56. | |
class-wc-logger.php | File | 9601 bytes | May 12 2025 21:07:28. | |
class-wc-meta-data.php | File | 2260 bytes | April 20 2022 06:50:54. | |
class-wc-order-factory.php | File | 8728 bytes | April 30 2024 19:35:34. | |
class-wc-order-item-coupon.php | File | 4175 bytes | December 22 2021 00:24:58. | |
class-wc-order-item-fee.php | File | 9431 bytes | March 03 2025 22:28:12. | |
class-wc-order-item-meta.php | File | 5942 bytes | December 22 2021 00:24:58. | |
class-wc-order-item-product.php | File | 16221 bytes | May 12 2025 21:07:28. | |
class-wc-order-item-shipping.php | File | 9013 bytes | May 12 2025 21:07:28. | |
class-wc-order-item-tax.php | File | 6644 bytes | December 22 2021 00:24:58. | |
class-wc-order-item.php | File | 18990 bytes | May 12 2025 21:07:28. | |
class-wc-order-query.php | File | 2615 bytes | July 28 2021 04:11:34. | |
class-wc-order-refund.php | File | 6135 bytes | May 12 2025 21:07:28. | |
class-wc-order.php | File | 76529 bytes | June 23 2025 19:46:28. | |
class-wc-payment-gateways.php | File | 16110 bytes | June 30 2025 17:49:22. | |
class-wc-payment-tokens.php | File | 6390 bytes | November 23 2022 05:58:58. | |
class-wc-post-data.php | File | 22246 bytes | March 03 2025 22:28:12. | |
class-wc-post-types.php | File | 32771 bytes | May 12 2025 21:07:28. | |
class-wc-privacy-background-process.php | File | 1833 bytes | March 03 2025 22:28:12. | |
class-wc-privacy-erasers.php | File | 13935 bytes | September 23 2024 20:44:04. | |
class-wc-privacy-exporters.php | File | 15044 bytes | July 28 2021 04:11:34. | |
class-wc-privacy.php | File | 17629 bytes | June 23 2025 19:46:28. | |
class-wc-product-attribute.php | File | 7137 bytes | January 19 2022 02:24:34. | |
class-wc-product-download.php | File | 12547 bytes | April 10 2024 16:54:10. | |
class-wc-product-external.php | File | 5104 bytes | March 03 2025 22:28:12. | |
class-wc-product-factory.php | File | 3974 bytes | January 21 2025 18:53:44. | |
class-wc-product-grouped.php | File | 5737 bytes | May 12 2025 21:07:28. | |
class-wc-product-query.php | File | 2332 bytes | January 21 2025 18:53:44. | |
class-wc-product-simple.php | File | 2762 bytes | January 21 2025 18:53:44. | |
class-wc-product-variable.php | File | 25166 bytes | June 02 2025 15:59:32. | |
class-wc-product-variation.php | File | 20661 bytes | May 12 2025 21:07:28. | |
class-wc-query.php | File | 34161 bytes | May 12 2025 21:07:28. | |
class-wc-rate-limiter.php | File | 4100 bytes | December 01 2021 04:23:30. | |
class-wc-regenerate-images-request.php | File | 7923 bytes | January 25 2023 03:19:12. | |
class-wc-regenerate-images.php | File | 15806 bytes | June 25 2024 21:17:40. | |
class-wc-register-wp-admin-settings.php | File | 5171 bytes | June 22 2021 15:24:06. | |
class-wc-rest-authentication.php | File | 22068 bytes | June 25 2024 21:17:40. | |
class-wc-rest-exception.php | File | 276 bytes | September 23 2020 01:16:50. | |
class-wc-session-handler.php | File | 21358 bytes | July 14 2025 13:28:08. | |
class-wc-shipping-rate.php | File | 9566 bytes | June 23 2025 19:46:28. | |
class-wc-shipping-zone.php | File | 13392 bytes | September 23 2020 01:16:50. | |
class-wc-shipping-zones.php | File | 4106 bytes | August 20 2020 23:18:50. | |
class-wc-shipping.php | File | 13160 bytes | May 12 2025 21:07:28. | |
class-wc-shortcodes.php | File | 19274 bytes | January 21 2025 18:53:44. | |
class-wc-structured-data.php | File | 24367 bytes | March 03 2025 22:28:12. | |
class-wc-tax.php | File | 37969 bytes | June 20 2023 23:45:50. | |
class-wc-template-loader.php | File | 21893 bytes | June 09 2025 15:55:46. | |
class-wc-tracker.php | File | 50557 bytes | June 23 2025 19:46:28. | |
class-wc-validation.php | File | 5929 bytes | May 28 2024 14:28:20. | |
class-wc-webhook.php | File | 30111 bytes | December 18 2024 22:19:16. | |
class-woocommerce.php | File | 51138 bytes | July 23 2025 12:38:10. | |
wc-account-functions.php | File | 14449 bytes | June 23 2025 19:46:28. | |
wc-attribute-functions.php | File | 21687 bytes | January 21 2025 18:53:44. | |
wc-brands-functions.php | File | 4270 bytes | September 23 2024 20:44:04. | |
wc-cart-functions.php | File | 21080 bytes | June 30 2025 17:49:22. | |
wc-conditional-functions.php | File | 14916 bytes | June 23 2025 19:46:28. | |
wc-core-functions.php | File | 88756 bytes | June 30 2025 17:49:22. | |
wc-coupon-functions.php | File | 3169 bytes | May 12 2025 21:07:28. | |
wc-deprecated-functions.php | File | 39030 bytes | May 12 2025 21:07:28. | |
wc-formatting-functions.php | File | 50031 bytes | June 30 2025 17:49:22. | |
wc-notice-functions.php | File | 8277 bytes | June 23 2025 19:46:28. | |
wc-order-functions.php | File | 41609 bytes | June 23 2025 19:46:28. | |
wc-order-item-functions.php | File | 5153 bytes | January 25 2023 03:19:12. | |
wc-order-step-logger-functions.php | File | 5135 bytes | May 12 2025 21:07:28. | |
wc-page-functions.php | File | 9657 bytes | September 23 2024 20:44:04. | |
wc-product-functions.php | File | 59920 bytes | June 23 2025 19:46:28. | |
wc-rest-functions.php | File | 14176 bytes | June 23 2025 19:46:28. | |
wc-stock-functions.php | File | 17544 bytes | January 21 2025 18:53:44. | |
wc-template-functions.php | File | 135937 bytes | June 23 2025 19:46:28. | |
wc-template-hooks.php | File | 12957 bytes | May 12 2025 21:07:28. | |
wc-term-functions.php | File | 24381 bytes | June 16 2025 19:21:28. | |
wc-update-functions.php | File | 95221 bytes | June 23 2025 19:46:28. | |
wc-user-functions.php | File | 35023 bytes | June 23 2025 19:46:28. | |
wc-webhook-functions.php | File | 5905 bytes | June 25 2024 21:17:40. | |
wc-widget-functions.php | File | 2063 bytes | August 20 2020 23:18:50. |
<?php /** * Download handler * * Handle digital downloads. * * @package WooCommerce\Classes * @version 2.2.0 */ defined( 'ABSPATH' ) || exit; /** * Download handler class. */ class WC_Download_Handler { /** * The hook used for deferred tracking of partial download attempts. */ public const TRACK_DOWNLOAD_CALLBACK = 'track_partial_download'; /** * Hook in methods. */ public static function init() { if ( isset( $_GET['download_file'], $_GET['order'] ) && ( isset( $_GET['email'] ) || isset( $_GET['uid'] ) ) ) { // WPCS: input var ok, CSRF ok. add_action( 'init', array( __CLASS__, 'download_product' ) ); } add_action( 'woocommerce_download_file_redirect', array( __CLASS__, 'download_file_redirect' ), 10, 2 ); add_action( 'woocommerce_download_file_xsendfile', array( __CLASS__, 'download_file_xsendfile' ), 10, 2 ); add_action( 'woocommerce_download_file_force', array( __CLASS__, 'download_file_force' ), 10, 2 ); add_action( self::TRACK_DOWNLOAD_CALLBACK, array( __CLASS__, 'track_download' ), 10, 3 ); } /** * Check if we need to download a file and check validity. */ public static function download_product() { // phpcs:disable WordPress.Security.NonceVerification.Recommended $product_id = absint( $_GET['download_file'] ); // phpcs:ignore WordPress.VIP.SuperGlobalInputUsage.AccessDetected, WordPress.VIP.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.ValidatedSanitizedInput.InputNotValidated $product = wc_get_product( $product_id ); $downloads = $product ? $product->get_downloads() : array(); $data_store = WC_Data_Store::load( 'customer-download' ); $key = empty( $_GET['key'] ) ? '' : sanitize_text_field( wp_unslash( $_GET['key'] ) ); if ( ! $product || empty( $key ) || empty( $_GET['order'] ) || ! isset( $downloads[ $key ] ) || ! $downloads[ $key ]->get_enabled() ) { self::download_error( __( 'Invalid download link.', 'woocommerce' ) ); } // Fallback, accept email address if it's passed. if ( empty( $_GET['email'] ) && empty( $_GET['uid'] ) ) { // WPCS: input var ok, CSRF ok. self::download_error( __( 'Invalid download link.', 'woocommerce' ) ); } // phpcs:enable WordPress.Security.NonceVerification.Recommended $order_id = wc_get_order_id_by_order_key( wc_clean( wp_unslash( $_GET['order'] ) ) ); // WPCS: input var ok, CSRF ok. $order = wc_get_order( $order_id ); if ( isset( $_GET['email'] ) ) { // WPCS: input var ok, CSRF ok. $email_address = wp_unslash( $_GET['email'] ); // WPCS: input var ok, CSRF ok, sanitization ok. } else { // Get email address from order to verify hash. $email_address = is_a( $order, 'WC_Order' ) ? $order->get_billing_email() : null; // Prepare email address hash. $email_hash = function_exists( 'hash' ) ? hash( 'sha256', $email_address ) : sha1( $email_address ); if ( is_null( $email_address ) || ! hash_equals( wp_unslash( $_GET['uid'] ), $email_hash ) ) { // WPCS: input var ok, CSRF ok, sanitization ok. self::download_error( __( 'Invalid download link.', 'woocommerce' ) ); } } $download_ids = $data_store->get_downloads( array( 'user_email' => sanitize_email( str_replace( ' ', '+', $email_address ) ), 'order_key' => wc_clean( wp_unslash( $_GET['order'] ) ), // WPCS: input var ok, CSRF ok. 'product_id' => $product_id, 'download_id' => wc_clean( preg_replace( '/\s+/', ' ', wp_unslash( $_GET['key'] ) ) ), // WPCS: input var ok, CSRF ok, sanitization ok. 'orderby' => 'downloads_remaining', 'order' => 'DESC', 'limit' => 1, 'return' => 'ids', ) ); if ( empty( $download_ids ) ) { self::download_error( __( 'Invalid download link.', 'woocommerce' ) ); } $download = new WC_Customer_Download( current( $download_ids ) ); /** * Filter download filepath. * * @since 4.0.0 * @param string $file_path File path. * @param string $email_address Email address. * @param WC_Order|bool $order Order object or false. * @param WC_Product $product Product object. * @param WC_Customer_Download $download Download data. */ $file_path = apply_filters( 'woocommerce_download_product_filepath', $product->get_file_download_path( $download->get_download_id() ), $email_address, $order, $product, $download ); $parsed_file_path = self::parse_file_path( $file_path ); $download_range = self::get_download_range( @filesize( $parsed_file_path['file_path'] ) ); // @codingStandardsIgnoreLine. self::check_order_is_valid( $download ); if ( ! $download_range['is_range_request'] ) { // If the remaining download count goes to 0, allow range requests to be able to finish streaming from iOS devices. self::check_downloads_remaining( $download ); } self::check_download_expiry( $download ); self::check_download_login_required( $download ); do_action( 'woocommerce_download_product', $download->get_user_email(), $download->get_order_key(), $download->get_product_id(), $download->get_user_id(), $download->get_download_id(), $download->get_order_id() ); $download->save(); // Track the download in logs and change remaining/counts. $current_user_id = get_current_user_id(); $ip_address = WC_Geolocation::get_ip_address(); self::track_download( $download, $current_user_id > 0 ? $current_user_id : null, ! empty( $ip_address ) ? $ip_address : null, $download_range['is_range_request'] ); self::download( $file_path, $download->get_product_id() ); } /** * Check if an order is valid for downloading from. * * @param WC_Customer_Download $download Download instance. */ private static function check_order_is_valid( $download ) { if ( $download->get_order_id() ) { $order = wc_get_order( $download->get_order_id() ); if ( $order && ! $order->is_download_permitted() ) { self::download_error( __( 'Invalid order.', 'woocommerce' ), '', 403 ); } } } /** * Check if there are downloads remaining. * * @param WC_Customer_Download $download Download instance. */ private static function check_downloads_remaining( $download ) { if ( '' !== $download->get_downloads_remaining() && 0 >= $download->get_downloads_remaining() ) { self::download_error( __( 'Sorry, you have reached your download limit for this file', 'woocommerce' ), '', 403 ); } } /** * Check if the download has expired. * * @param WC_Customer_Download $download Download instance. */ private static function check_download_expiry( $download ) { if ( ! is_null( $download->get_access_expires() ) && $download->get_access_expires()->getTimestamp() < strtotime( 'midnight', time() ) ) { self::download_error( __( 'Sorry, this download has expired', 'woocommerce' ), '', 403 ); } } /** * Check if a download requires the user to login first. * * @param WC_Customer_Download $download Download instance. */ private static function check_download_login_required( $download ) { if ( $download->get_user_id() && 'yes' === get_option( 'woocommerce_downloads_require_login' ) ) { if ( ! is_user_logged_in() ) { if ( wc_get_page_id( 'myaccount' ) ) { wp_safe_redirect( add_query_arg( 'wc_error', rawurlencode( __( 'You must be logged in to download files.', 'woocommerce' ) ), wc_get_page_permalink( 'myaccount' ) ) ); exit; } else { self::download_error( __( 'You must be logged in to download files.', 'woocommerce' ) . ' <a href="' . esc_url( wp_login_url( wc_get_page_permalink( 'myaccount' ) ) ) . '" class="wc-forward">' . __( 'Login', 'woocommerce' ) . '</a>', __( 'Log in to Download Files', 'woocommerce' ), 403 ); } } elseif ( ! current_user_can( 'download_file', $download ) ) { self::download_error( __( 'This is not your download link.', 'woocommerce' ), '', 403 ); } } } /** * Count download. * * @deprecated 4.4.0 * @param array $download_data Download data. */ public static function count_download( $download_data ) { wc_deprecated_function( 'WC_Download_Handler::count_download', '4.4.0', '' ); } /** * Download a file - hook into init function. * * @param string $file_path URL to file. * @param integer $product_id Product ID of the product being downloaded. */ public static function download( $file_path, $product_id ) { if ( ! $file_path ) { self::download_error( __( 'No file defined', 'woocommerce' ) ); } $filename = basename( $file_path ); if ( strstr( $filename, '?' ) ) { $filename = current( explode( '?', $filename ) ); } $filename = apply_filters( 'woocommerce_file_download_filename', $filename, $product_id ); /** * Filter download method. * * @since 4.5.0 * @param string $method Download method. * @param int $product_id Product ID. * @param string $file_path URL to file. */ $file_download_method = apply_filters( 'woocommerce_file_download_method', get_option( 'woocommerce_file_download_method', 'force' ), $product_id, $file_path ); // Add action to prevent issues in IE. add_action( 'nocache_headers', array( __CLASS__, 'ie_nocache_headers_fix' ) ); // Trigger download via one of the methods. do_action( 'woocommerce_download_file_' . $file_download_method, $file_path, $filename ); } /** * Redirect to a file to start the download. * * @param string $file_path File path. * @param string $filename File name. */ public static function download_file_redirect( $file_path, $filename = '' ) { header( 'Location: ' . $file_path ); exit; } /** * Parse file path and see if its remote or local. * * @param string $file_path File path. * @return array */ public static function parse_file_path( $file_path ) { $wp_uploads = wp_upload_dir(); $wp_uploads_dir = $wp_uploads['basedir']; $wp_uploads_url = $wp_uploads['baseurl']; /** * Replace uploads dir, site url etc with absolute counterparts if we can. * Note the str_replace on site_url is on purpose, so if https is forced * via filters we can still do the string replacement on a HTTP file. */ $replacements = array( $wp_uploads_url => $wp_uploads_dir, network_site_url( '/', 'https' ) => ABSPATH, str_replace( 'https:', 'http:', network_site_url( '/', 'http' ) ) => ABSPATH, site_url( '/', 'https' ) => ABSPATH, str_replace( 'https:', 'http:', site_url( '/', 'http' ) ) => ABSPATH, ); $count = 0; $file_path = str_replace( array_keys( $replacements ), array_values( $replacements ), $file_path, $count ); $parsed_file_path = wp_parse_url( $file_path ); $remote_file = null === $count || 0 === $count; // Remote file only if there were no replacements. // Paths that begin with '//' are always remote URLs. if ( '//' === substr( $file_path, 0, 2 ) ) { $file_path = ( is_ssl() ? 'https:' : 'http:' ) . $file_path; /** * Filter the remote filepath for download. * * @since 6.5.0 * @param string $file_path File path. */ return array( 'remote_file' => true, 'file_path' => apply_filters( 'woocommerce_download_parse_remote_file_path', $file_path ), ); } // See if path needs an abspath prepended to work. if ( file_exists( ABSPATH . $file_path ) ) { $remote_file = false; $file_path = ABSPATH . $file_path; } elseif ( '/wp-content' === substr( $file_path, 0, 11 ) ) { $remote_file = false; $file_path = realpath( WP_CONTENT_DIR . substr( $file_path, 11 ) ); // Check if we have an absolute path. } elseif ( ( ! isset( $parsed_file_path['scheme'] ) || ! in_array( $parsed_file_path['scheme'], array( 'http', 'https', 'ftp' ), true ) ) && isset( $parsed_file_path['path'] ) ) { $remote_file = false; $file_path = $parsed_file_path['path']; } /** * Filter the filepath for download. * * @since 6.5.0 * @param string $file_path File path. * @param bool $remote_file Remote File Indicator. */ return array( 'remote_file' => $remote_file, 'file_path' => apply_filters( 'woocommerce_download_parse_file_path', $file_path, $remote_file ), ); } /** * Download a file using X-Sendfile, X-Lighttpd-Sendfile, or X-Accel-Redirect if available. * * @param string $file_path File path. * @param string $filename File name. */ public static function download_file_xsendfile( $file_path, $filename ) { $parsed_file_path = self::parse_file_path( $file_path ); /** * Fallback on force download method for remote files. This is because: * 1. xsendfile needs proxy configuration to work for remote files, which cannot be assumed to be available on most hosts. * 2. Force download method is more secure than redirect method if `allow_url_fopen` is enabled in `php.ini`. */ if ( $parsed_file_path['remote_file'] && ! apply_filters( 'woocommerce_use_xsendfile_for_remote', false ) ) { do_action( 'woocommerce_download_file_force', $file_path, $filename ); return; } if ( function_exists( 'apache_get_modules' ) && in_array( 'mod_xsendfile', apache_get_modules(), true ) ) { self::download_headers( $parsed_file_path['file_path'], $filename ); $filepath = apply_filters( 'woocommerce_download_file_xsendfile_file_path', $parsed_file_path['file_path'], $file_path, $filename, $parsed_file_path ); header( 'X-Sendfile: ' . $filepath ); exit; } elseif ( stristr( getenv( 'SERVER_SOFTWARE' ), 'lighttpd' ) ) { self::download_headers( $parsed_file_path['file_path'], $filename ); $filepath = apply_filters( 'woocommerce_download_file_xsendfile_lighttpd_file_path', $parsed_file_path['file_path'], $file_path, $filename, $parsed_file_path ); header( 'X-Lighttpd-Sendfile: ' . $filepath ); exit; } elseif ( stristr( getenv( 'SERVER_SOFTWARE' ), 'nginx' ) || stristr( getenv( 'SERVER_SOFTWARE' ), 'cherokee' ) ) { self::download_headers( $parsed_file_path['file_path'], $filename ); $xsendfile_path = trim( preg_replace( '`^' . str_replace( '\\', '/', getcwd() ) . '`', '', $parsed_file_path['file_path'] ), '/' ); $xsendfile_path = apply_filters( 'woocommerce_download_file_xsendfile_x_accel_redirect_file_path', $xsendfile_path, $file_path, $filename, $parsed_file_path ); header( "X-Accel-Redirect: /$xsendfile_path" ); exit; } // Fallback. wc_get_logger()->warning( sprintf( /* translators: %1$s contains the filepath of the digital asset. */ __( '%1$s could not be served using the X-Accel-Redirect/X-Sendfile method. A Force Download will be used instead.', 'woocommerce' ), $file_path ) ); self::download_file_force( $file_path, $filename ); } /** * Parse the HTTP_RANGE request from iOS devices. * Does not support multi-range requests. * * @param int $file_size Size of file in bytes. * @return array { * Information about range download request: beginning and length of * file chunk, whether the range is valid/supported and whether the request is a range request. * * @type int $start Byte offset of the beginning of the range. Default 0. * @type int $length Length of the requested file chunk in bytes. Optional. * @type bool $is_range_valid Whether the requested range is a valid and supported range. * @type bool $is_range_request Whether the request is a range request. * } */ protected static function get_download_range( $file_size ) { $start = 0; $download_range = array( 'start' => $start, 'is_range_valid' => false, 'is_range_request' => false, ); if ( ! $file_size ) { return $download_range; } $end = $file_size - 1; $download_range['length'] = $file_size; if ( isset( $_SERVER['HTTP_RANGE'] ) ) { // @codingStandardsIgnoreLine. $http_range = sanitize_text_field( wp_unslash( $_SERVER['HTTP_RANGE'] ) ); // WPCS: input var ok. $download_range['is_range_request'] = true; $c_start = $start; $c_end = $end; // Extract the range string. list( , $range ) = explode( '=', $http_range, 2 ); // Make sure the client hasn't sent us a multibyte range. if ( strpos( $range, ',' ) !== false ) { return $download_range; } /* * If the range starts with an '-' we start from the beginning. * If not, we forward the file pointer * and make sure to get the end byte if specified. */ if ( '-' === $range[0] ) { // The n-number of the last bytes is requested. $c_start = $file_size - substr( $range, 1 ); } else { $range = explode( '-', $range ); $c_start = ( isset( $range[0] ) && is_numeric( $range[0] ) ) ? (int) $range[0] : 0; $c_end = ( isset( $range[1] ) && is_numeric( $range[1] ) ) ? (int) $range[1] : $file_size; } /* * Check the range and make sure it's treated according to the specs: http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html. * End bytes can not be larger than $end. */ $c_end = ( $c_end > $end ) ? $end : $c_end; // Validate the requested range and return an error if it's not correct. if ( $c_start > $c_end || $c_start > $file_size - 1 || $c_end >= $file_size ) { return $download_range; } $start = $c_start; $end = $c_end; $length = $end - $start + 1; $download_range['start'] = $start; $download_range['length'] = $length; $download_range['is_range_valid'] = true; } return $download_range; } /** * Force download - this is the default method. * * @param string $file_path File path. * @param string $filename File name. */ public static function download_file_force( $file_path, $filename ) { $parsed_file_path = self::parse_file_path( $file_path ); $download_range = self::get_download_range( @filesize( $parsed_file_path['file_path'] ) ); // @codingStandardsIgnoreLine. self::download_headers( $parsed_file_path['file_path'], $filename, $download_range ); $start = isset( $download_range['start'] ) ? $download_range['start'] : 0; $length = isset( $download_range['length'] ) ? $download_range['length'] : 0; if ( ! self::readfile_chunked( $parsed_file_path['file_path'], $start, $length ) ) { if ( $parsed_file_path['remote_file'] && 'yes' === get_option( 'woocommerce_downloads_redirect_fallback_allowed' ) ) { wc_get_logger()->warning( sprintf( /* translators: %1$s contains the filepath of the digital asset. */ __( '%1$s could not be served using the Force Download method. A redirect will be used instead.', 'woocommerce' ), $file_path ) ); self::download_file_redirect( $file_path ); } else { self::download_error( __( 'File not found', 'woocommerce' ) ); } } exit; } /** * Get content type of a download. * * @param string $file_path File path. * @return string */ private static function get_download_content_type( $file_path ) { $file_extension = strtolower( substr( strrchr( $file_path, '.' ), 1 ) ); $ctype = 'application/force-download'; foreach ( get_allowed_mime_types() as $mime => $type ) { $mimes = explode( '|', $mime ); if ( in_array( $file_extension, $mimes, true ) ) { $ctype = $type; break; } } return $ctype; } /** * Set headers for the download. * * @param string $file_path File path. * @param string $filename File name. * @param array $download_range Array containing info about range download request (see {@see get_download_range} for structure). */ private static function download_headers( $file_path, $filename, $download_range = array() ) { self::check_server_config(); self::clean_buffers(); wc_nocache_headers(); header( 'X-Robots-Tag: noindex, nofollow', true ); header( 'Content-Type: ' . self::get_download_content_type( $file_path ) ); header( 'Content-Description: File Transfer' ); header( 'Content-Disposition: ' . self::get_content_disposition() . '; filename="' . $filename . '";' ); header( 'Content-Transfer-Encoding: binary' ); $file_size = @filesize( $file_path ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged if ( ! $file_size ) { return; } if ( isset( $download_range['is_range_request'] ) && true === $download_range['is_range_request'] ) { if ( false === $download_range['is_range_valid'] ) { header( 'HTTP/1.1 416 Requested Range Not Satisfiable' ); header( 'Content-Range: bytes 0-' . ( $file_size - 1 ) . '/' . $file_size ); exit; } $start = $download_range['start']; $end = $download_range['start'] + $download_range['length'] - 1; $length = $download_range['length']; header( 'HTTP/1.1 206 Partial Content' ); header( "Accept-Ranges: 0-$file_size" ); header( "Content-Range: bytes $start-$end/$file_size" ); header( "Content-Length: $length" ); } else { header( 'Content-Length: ' . $file_size ); } } /** * Check and set certain server config variables to ensure downloads work as intended. */ private static function check_server_config() { wc_set_time_limit( 0 ); if ( function_exists( 'apache_setenv' ) ) { @apache_setenv( 'no-gzip', 1 ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_apache_setenv } @ini_set( 'zlib.output_compression', 'Off' ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_ini_set @session_write_close(); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.VIP.SessionFunctionsUsage.session_session_write_close } /** * Clean all output buffers. * * Can prevent errors, for example: transfer closed with 3 bytes remaining to read. */ private static function clean_buffers() { if ( ob_get_level() ) { $levels = ob_get_level(); for ( $i = 0; $i < $levels; $i++ ) { @ob_end_clean(); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } } else { @ob_end_clean(); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } } /** * * Get selected content disposition * * Defaults to attachment if `woocommerce_downloads_deliver_inline` setting is not selected. * * @return string Content disposition value. */ private static function get_content_disposition() : string { $disposition = 'attachment'; if ( 'yes' === get_option( 'woocommerce_downloads_deliver_inline' ) ) { $disposition = 'inline'; } return $disposition; } /** * Read file chunked. * * Reads file in chunks so big downloads are possible without changing PHP.INI - http://codeigniter.com/wiki/Download_helper_for_large_files/. * * @param string $file File. * @param int $start Byte offset/position of the beginning from which to read from the file. * @param int $length Length of the chunk to be read from the file in bytes, 0 means full file. * @return bool Success or fail */ public static function readfile_chunked( $file, $start = 0, $length = 0 ) { if ( ! defined( 'WC_CHUNK_SIZE' ) ) { define( 'WC_CHUNK_SIZE', 1024 * 1024 ); } $handle = @fopen( $file, 'r' ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_read_fopen if ( false === $handle ) { return false; } if ( ! $length ) { $length = @filesize( $file ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged } $read_length = (int) WC_CHUNK_SIZE; if ( $length ) { $end = $start + $length - 1; @fseek( $handle, $start ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged $p = @ftell( $handle ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged while ( ! @feof( $handle ) && $p <= $end ) { // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged // Don't run past the end of file. if ( $p + $read_length > $end ) { $read_length = $end - $p + 1; } echo @fread( $handle, $read_length ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.XSS.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions.file_system_read_fread $p = @ftell( $handle ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged if ( ob_get_length() ) { ob_flush(); flush(); } } } else { while ( ! @feof( $handle ) ) { // @codingStandardsIgnoreLine. echo @fread( $handle, $read_length ); // @codingStandardsIgnoreLine. if ( ob_get_length() ) { ob_flush(); flush(); } } } return @fclose( $handle ); // phpcs:ignore Generic.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_read_fclose } /** * Filter headers for IE to fix issues over SSL. * * IE bug prevents download via SSL when Cache Control and Pragma no-cache headers set. * * @param array $headers HTTP headers. * @return array */ public static function ie_nocache_headers_fix( $headers ) { if ( is_ssl() && ! empty( $GLOBALS['is_IE'] ) ) { $headers['Cache-Control'] = 'private'; unset( $headers['Pragma'] ); } return $headers; } /** * Die with an error message if the download fails. * * @param string $message Error message. * @param string $title Error title. * @param integer $status Error status. */ private static function download_error( $message, $title = '', $status = 404 ) { /* * Since we will now render a message instead of serving a download, we should unwind some of the previously set * headers. */ if ( headers_sent() ) { wc_get_logger()->log( 'warning', __( 'Headers already sent when generating download error message.', 'woocommerce' ) ); } else { header( 'Content-Type: ' . get_option( 'html_type' ) . '; charset=' . get_option( 'blog_charset' ) ); header_remove( 'Content-Description;' ); header_remove( 'Content-Disposition' ); header_remove( 'Content-Transfer-Encoding' ); } if ( ! strstr( $message, '<a ' ) ) { $message .= ' <a href="' . esc_url( wc_get_page_permalink( 'shop' ) ) . '" class="wc-forward">' . esc_html__( 'Go to shop', 'woocommerce' ) . '</a>'; } wp_die( $message, $title, array( 'response' => $status ) ); // WPCS: XSS ok. } /** * Takes care of tracking download requests, with support for deferring tracking in the case of * partial (ranged request) downloads. * * @param WC_Customer_Download|int $download The download to be tracked. * @param int|null $user_id The user ID, if known. * @param string|null $user_ip_address The download IP address, if known. * @param bool $defer If tracking the download should be deferred. * * @return void * @throws Exception If the active version of Action Scheduler is less than 3.6.0. * * @internal For exclusive usage of WooCommerce core, backwards compatibility not guaranteed. */ public static function track_download( $download, $user_id = null, $user_ip_address = null, bool $defer = false ): void { try { // If we were supplied with an integer, convert it to a download object. $download = new WC_Customer_Download( $download ); // In simple cases, we can track the download immediately. if ( ! $defer ) { $download->track_download( $user_id, $user_ip_address ); return; } // Counting of partial downloads may be disabled by the site operator. if ( get_option( 'woocommerce_downloads_count_partial', 'yes' ) !== 'yes' ) { return; } /** * Determines how long the window of time is for tracking unique download attempts, in relation to * partial (ranged) download requests. * * @since 9.2.0 * * @param int $window_in_seconds Non-negative number of seconds. Defaults to 1800 (30 minutes). * @param int $download_permission_id References the download permission being tracked. */ $window = absint( apply_filters( 'woocommerce_partial_download_tracking_window', 30 * MINUTE_IN_SECONDS, $download->get_id() ) ); // If we do not have Action Scheduler 3.6.0+ (this would be an unexpected scenario) then we cannot // track partial downloads, because we require support for unique actions. if ( version_compare( ActionScheduler_Versions::instance()->latest_version(), '3.6.0', '<' ) ) { throw new Exception( 'Support for unique scheduled actions is not currently available.' ); } as_schedule_single_action( time() + $window, self::TRACK_DOWNLOAD_CALLBACK, array( $download->get_id(), $user_id, $user_ip_address, ), 'woocommerce', true ); } catch ( Exception $e ) { wc_get_logger()->error( 'There was a problem while tracking a product download.', array( 'error' => $e->getMessage(), 'id' => $download->get_id(), 'user_id' => $user_id, 'ip' => $user_ip_address, 'deferred' => $defer ? 'yes' : 'no', ) ); } } } WC_Download_Handler::init();
SILENT KILLER Tool