WC_Download_Handler::download_product │ public static │ WC 1.0
Check if we need to download a file and check validity.
Method of the class: WC_Download_Handler{}
Hooks from the method
Returns
null. Nothing (null).
Usage
$result = WC_Download_Handler::download_product();
WC_Download_Handler::download_product() WC Download Handler::download product code WC 11.2.2
public static function download_product() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Emailed download links are bearer URLs: authorization is the order key plus the billing email or its hash, both verified below, so no nonce can be issued for them.
// Download links only ever carry scalar values, so reject array input instead of passing it to the string handling below.
foreach ( array( 'download_file', 'order', 'key', 'email', 'uid' ) as $download_arg ) {
if ( isset( $_GET[ $download_arg ] ) && ! is_scalar( $_GET[ $download_arg ] ) ) {
self::download_error( __( 'Invalid download link.', 'woocommerce' ) );
}
}
$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'] ) );
$order_key = empty( $_GET['order'] ) ? '' : wc_clean( wp_unslash( $_GET['order'] ) );
if (
! $product
|| empty( $key )
|| empty( $order_key )
|| ! 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'] ) ) {
self::download_error( __( 'Invalid download link.', 'woocommerce' ) );
}
$order_id = wc_get_order_id_by_order_key( $order_key );
$order = wc_get_order( $order_id );
if ( isset( $_GET['email'] ) ) {
$email_address = wp_unslash( $_GET['email'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- The raw value is needed so spaces can be restored to "+" below; sanitize_email() is applied before the lookup.
} 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 ) ) {
self::download_error( __( 'Invalid download link.', 'woocommerce' ) );
}
}
$user_email = sanitize_email( str_replace( ' ', '+', $email_address ) );
if ( empty( $user_email ) ) {
self::download_error( __( 'Invalid download link.', 'woocommerce' ) );
}
$download_ids = $data_store->get_downloads(
array(
'user_email' => $user_email,
'order_key' => $order_key,
'product_id' => $product_id,
'download_id' => wc_clean( preg_replace( '/\s+/', ' ', wp_unslash( $_GET['key'] ) ) ), // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- The key is matched against the product's download list above and wc_clean() normalizes it before the lookup.
'orderby' => 'downloads_remaining',
'order' => 'DESC',
'limit' => 1,
'return' => 'ids',
)
);
// phpcs:enable WordPress.Security.NonceVerification.Recommended
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() );
}