• Resolved nikdow

    (@nikdow)


    A while ago I started thread here:
    https://wordpress.org/support/topic/x-sendfile-with-php-fpm/

    It’s now closed but in case anyone has the same issue, here is the solution, pretty much along the lines suggested by support.

    Below is a code snippet which I added into the customisations plugin, or you could add it to a child theme’s functions.php.

    The problem arises with WooCommerce file downloads if you are running apache and php FPM. WooCommerce can’t detect X-Sendfile because FPM doesn’t have the required function.
    So the following code copies the WC code with the X-Sendfile check removed.

    /* force X-Sendfile despite php-fpm */
    remove_action( 'woocommerce_download_file_xsendfile', array( WC_Download_Handler::class, 'download_file_xsendfile' ) );

    // Hook your custom function into WooCommerce's download handler
    add_action('woocommerce_download_file_xsendfile', [ spelfabet_download_handler::class, 'download_file_xsendfile'], 10, 2);

    class spelfabet_download_handler{

    public static function download_file_xsendfile( $file_path, $filename ) {
    $parsed_file_path = WC_Download_Handler::parse_file_path( $file_path );

    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;
    }
    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 );
    }
    }
    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
    }
    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
    }
    }
    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;
    }
    private static function get_content_disposition() : string {
    $disposition = 'attachment';
    if ( 'yes' === get_option( 'woocommerce_downloads_deliver_inline' ) ) {
    $disposition = 'inline';
    }
    return $disposition;
    }
    }

    The page I need help with: [log in to see the link]

The topic ‘[WooCommerce] x-sendfile with php-fpm’ is closed to new replies.