1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
|
<?php declare( strict_types=1 );
namespace Automattic\WooCommerce\Internal\Admin\Logging\FileV2;
use Automattic\WooCommerce\Internal\Utilities\FilesystemUtil; use Exception; use WP_Error;
/** * FileExport class. */ class FileExporter { /** * The number of bytes per read while streaming the file. * * @const int */ private const CHUNK_SIZE = 4 * KB_IN_BYTES;
/** * The absolute path of the file. * * @var string */ private $path;
/** * A name of the file to send to the browser rather than the filename part of the path. * * @var string */ private $alternate_filename;
/** * Class FileExporter. * * @param string $path The absolute path of the file. * @param string $alternate_filename Optional. The name of the file to send to the browser rather than the filename * part of the path. */ public function __construct( string $path, string $alternate_filename = '' ) { $this->path = $path; $this->alternate_filename = $alternate_filename; }
/** * Configure PHP and stream the file to the browser. * * @return WP_Error|void Only returns something if there is an error. */ public function emit_file() { try { $filesystem = FilesystemUtil::get_wp_filesystem(); $is_readable = $filesystem->is_file( $this->path ) && $filesystem->is_readable( $this->path ); } catch ( Exception $exception ) { $is_readable = false; }
if ( ! $is_readable ) { return new WP_Error( 'wc_logs_invalid_file', __( 'Could not access file.', 'woocommerce' ) ); }
// These configuration tweaks are copied from WC_CSV_Exporter::send_headers(). // phpcs:disable WordPress.PHP.NoSilencedErrors.Discouraged if ( function_exists( 'gc_enable' ) ) { gc_enable(); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.gc_enableFound } if ( function_exists( 'apache_setenv' ) ) { @apache_setenv( 'no-gzip', '1' ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_apache_setenv } @ini_set( 'zlib.output_compression', 'Off' ); // phpcs:ignore WordPress.PHP.IniSet.Risky @ini_set( 'output_buffering', 'Off' ); // phpcs:ignore WordPress.PHP.IniSet.Risky @ini_set( 'output_handler', '' ); // phpcs:ignore WordPress.PHP.IniSet.Risky ignore_user_abort( true ); wc_set_time_limit(); wc_nocache_headers(); // phpcs:enable WordPress.PHP.NoSilencedErrors.Discouraged
$this->send_headers(); $this->send_contents();
die; }
/** * Send HTTP headers at the beginning of a file. * * Modeled on WC_CSV_Exporter::send_headers(). * * @return void */ private function send_headers(): void { header( 'Content-Type: text/plain; charset=utf-8' ); header( 'Content-Disposition: attachment; filename=' . $this->get_filename() ); header( 'Pragma: no-cache' ); header( 'Expires: 0' ); }
/** * Send the contents of the file. * * @return void */ private function send_contents(): void { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- No suitable alternative. $stream = fopen( $this->path, 'rb' );
while ( is_resource( $stream ) && ! feof( $stream ) ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fread -- No suitable alternative. $chunk = fread( $stream, self::CHUNK_SIZE );
if ( is_string( $chunk ) ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Outputting to file. echo $chunk; } }
// phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- No suitable alternative. fclose( $stream ); }
/** * Get the name of the file that will be sent to the browser. * * @return string */ private function get_filename(): string { if ( $this->alternate_filename ) { return $this->alternate_filename; }
return basename( $this->path ); } }
|