$legacy_proxy->call_function( 'status_header', 404 );
$file_length = filesize( $file_path );
if ( false === $file_length ) {
throw new Exception( "Can't retrieve file size: $file_path" );
$file_handle = fopen( $file_path, 'r' );
} catch ( Exception $ex ) {
$error_message = "Error serving transient file $file_name: {$ex->getMessage()}";
wc_get_logger()->error( $error_message );
$legacy_proxy->call_function( 'status_header', 500 );
$legacy_proxy->call_function( 'status_header', 200 );
$legacy_proxy->call_function( 'header', 'Content-Type: text/html' );
$legacy_proxy->call_function( 'header', "Content-Length: $file_length" );
while ( ! feof( $file_handle ) ) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo fread( $file_handle, 1024 );
* Action that fires after a transient file has been successfully served, right before terminating the request.
* @param array $transient_file_info Information about the served file, as returned by get_file_by_name.
* @param bool $is_json_rest_api_request True if the request came from the JSON API endpoint, false if it came from the authenticated endpoint.
do_action( 'woocommerce_transient_file_contents_served', $file_name );
} catch ( Exception $e ) {
wc_get_logger()->error( "Error serving transient file $file_name: {$e->getMessage()}" );
// We can't change the response status code at this point.