PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 16.3-beta
Jetpack – WP Security, Backup, Speed, & Growth v16.3-beta
16.3 16.3-beta 16.3-a.5 16.3-a.7 16.3-a.3 16.3-a.1 16.2 16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 All 508 releases
← All changes | jetpack_vendor/automattic/jetpack-backup-helper-script-manager/src/class-throw-on-errors.php +498 -0 16.2-beta → 16.3-beta View file →
@@ -1,0 +1,498 @@
1 +<?php // phpcs:disable Squiz.Commenting.FileComment.Missing
2 +
3 +// phpcs:disable WordPress.PHP.DevelopmentFunctions.prevent_path_disclosure_error_reporting
4 +// phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting
5 +// phpcs:disable WordPress.PHP.IniSet.display_errors_Disallowed
6 +
7 +// After changing this file, consider increasing the version number ("VXXX") in all the files using this namespace, in
8 +// order to ensure that the specific version of this file always get loaded. Otherwise, Jetpack autoloader might decide
9 +// to load an older/newer version of the class (if, for example, both the standalone and bundled versions of the plugin
10 +// are installed, or in some other cases).
11 +namespace Automattic\Jetpack\Backup\V0005;
12 +
13 +use Exception;
14 +use Throwable;
15 +
16 +/**
17 + * Wrappers for functions which throw an exception on errors and warnings instead of silently continuing operation.
18 + *
19 + * PHP is pretty lax with error reporting when doing I/O operations, e.g. a typical I/O helper function returns false,
20 + * null, and/or emits a warning, but the whole PHP application continues operation. It's for the caller of the I/O
21 + * helper function to test the returned result of the function, and notice + act upon I/O errors.
22 + *
23 + * We really want to know about each and every I/O error. Therefore, this class provides wrappers for some common
24 + * (mostly) I/O operations that throw an exception on errors instead of just returning false, null, or something else.
25 + * This wrapper class treats warnings as errors too.
26 + *
27 + * Given that static method names are similar to the ones used by PHP, they're prefixed with "t_" to not erroneously
28 + * trigger various security scanners.
29 + */
30 +class Throw_On_Errors {
31 +
32 + /**
33 + * Execute a callable, throw an exception (together with a descriptive label) on PHP warnings / errors.
34 + *
35 + * @param callable $callable Callable to execute.
36 + * @param string $label Label to add to the thrown exception to clarify what was attempted.
37 + *
38 + * @return mixed Callable's return value, if any.
39 + * @throws Exception On warnings thrown by the callable.
40 + * @noinspection PhpUnusedParameterInspection
41 + */
42 + private static function throw_on_warnings( $callable, $label ) {
43 + $old_error_reporting = error_reporting( - 1 );
44 + $old_display_errors = ini_set( 'display_errors', 'stderr' );
45 +
46 + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler
47 + set_error_handler(
48 + /**
49 + * Temporary error handler.
50 + *
51 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.set-error-handler
52 + * @see https://www.php.net/manual/en/function.set-error-handler.php
53 + *
54 + * @param int $errno Level of the error raised.
55 + * @param string $errstr Error message.
56 + * @param string|null $errfile Filename that the error was raised in.
57 + * @param int|null $errline Line number where the error was raised.
58 + * @param array|null $errcontext Deprecated, unused.
59 + *
60 + * @return never
61 + * @throws Exception
62 + */
63 + // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
64 + function ( $errno, $errstr, $errfile = null, $errline = null, $errcontext = null ) {
65 + throw new Exception( "$errstr (file: $errfile; line: $errline)" );
66 + }
67 + );
68 +
69 + $result = null;
70 + $error_message = null;
71 + try {
72 + $result = $callable();
73 + } catch ( Throwable $throwable ) {
74 + $error_message = $throwable->getMessage();
75 + }
76 +
77 + restore_error_handler();
78 + ini_set( 'display_errors', $old_display_errors );
79 + error_reporting( $old_error_reporting );
80 +
81 + if ( $error_message !== null ) {
82 + throw new Exception( "$label failed: $error_message" );
83 + }
84 +
85 + return $result;
86 + }
87 +
88 + /**
89 + * Return canonicalized absolute pathname, throw on warnings / errors.
90 + *
91 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.realpath
92 + * @see https://www.php.net/manual/en/function.realpath.php
93 + *
94 + * @param string $path Path being checked.
95 + *
96 + * @return string Canonicalized absolute pathname
97 + * @throws Exception On invalid parameters, or if realpath() has returned false or thrown warnings.
98 + */
99 + public static function t_realpath( $path ) {
100 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
101 + if ( ! $path ) {
102 + throw new Exception( 'Filename for realpath() is unset' );
103 + }
104 +
105 + $label = "realpath( '$path' )";
106 +
107 + $realpath_result = static::throw_on_warnings(
108 + function () use ( $path ) {
109 + return realpath( $path );
110 + },
111 + $label
112 + );
113 +
114 + if ( false === $realpath_result ) {
115 + throw new Exception( "Unable to $label" );
116 + }
117 +
118 + return $realpath_result;
119 + }
120 +
121 + /**
122 + * Check whether a file or directory exists, throw on warnings / errors.
123 + *
124 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.file-exists
125 + * @see https://www.php.net/manual/en/function.file-exists.php
126 + *
127 + * @param string $filename Path to the file or directory.
128 + *
129 + * @return bool True if the file or directory specified by filename exists; false otherwise.
130 + * @throws Exception On invalid parameters, or if file_exists() has thrown warnings.
131 + */
132 + public static function t_file_exists( $filename ) {
133 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
134 + if ( ! $filename ) {
135 + throw new Exception( 'Filename for file_exists() is unset' );
136 + }
137 +
138 + return static::throw_on_warnings(
139 + function () use ( $filename ) {
140 + return file_exists( $filename );
141 + },
142 + "file_exists( '$filename' )"
143 + );
144 + }
145 +
146 + /**
147 + * Tell whether the filename (or a directory) is readable, throw on warnings / errors.
148 + *
149 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.is-readable
150 + * @see https://www.php.net/manual/en/function.is-readable.php
151 + *
152 + * @param string $filename Filename (or directory) to check.
153 + *
154 + * @return bool True if the filename (or a directory) exists and is readable, false otherwise.
155 + * @throws Exception On invalid parameters, or if is_readable() has thrown warnings.
156 + */
157 + public static function t_is_readable( $filename ) {
158 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
159 + if ( ! $filename ) {
160 + throw new Exception( 'Filename for is_readable() is unset' );
161 + }
162 +
163 + return static::throw_on_warnings(
164 + function () use ( $filename ) {
165 + return is_readable( $filename );
166 + },
167 + "is_readable( '$filename' )"
168 + );
169 + }
170 +
171 + /**
172 + * Tell whether the filename (or a directory) is writable, throw on warnings / errors.
173 + *
174 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.is-writable
175 + * @see https://www.php.net/manual/en/function.is-writable.php
176 + *
177 + * @param string $filename Filename (or directory) to check.
178 + *
179 + * @return bool True if the filename (or a directory) exists and is writable, false otherwise.
180 + * @throws Exception On invalid parameters, or if is_writable() has thrown warnings.
181 + */
182 + public static function t_is_writable( $filename ) {
183 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
184 + if ( ! $filename ) {
185 + throw new Exception( 'Filename for is_writable() is unset' );
186 + }
187 +
188 + return static::throw_on_warnings(
189 + function () use ( $filename ) {
190 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable
191 + return is_writable( $filename );
192 + },
193 + "is_writable( '$filename' )"
194 + );
195 + }
196 +
197 + /**
198 + * Get file size, throw on warnings / errors.
199 + *
200 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.filesize
201 + * @see https://www.php.net/manual/en/function.filesize.php
202 + *
203 + * @param string $filename Path to the file.
204 + *
205 + * @return int Size of the file in bytes
206 + * @throws Exception On invalid parameters, or if filesize() has thrown warnings.
207 + */
208 + public static function t_filesize( $filename ) {
209 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
210 + if ( ! $filename ) {
211 + throw new Exception( 'Filename for filesize() is unset' );
212 + }
213 +
214 + $label = "filesize( '$filename' )";
215 +
216 + $filesize_result = static::throw_on_warnings(
217 + function () use ( $filename ) {
218 + return filesize( $filename );
219 + },
220 + $label
221 + );
222 +
223 + if ( false === $filesize_result ) {
224 + throw new Exception( "Unable to $label" );
225 + }
226 +
227 + return $filesize_result;
228 + }
229 +
230 + /**
231 + * Get file modification time, throw on warnings / errors.
232 + *
233 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.filemtime
234 + * @see https://www.php.net/manual/en/function.filemtime.php
235 + *
236 + * @param string $filename Path to the file.
237 + *
238 + * @return int The time the file was last modified
239 + * @throws Exception On invalid parameters, or if filemtime() has thrown warnings.
240 + */
241 + public static function t_filemtime( $filename ) {
242 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
243 + if ( ! $filename ) {
244 + throw new Exception( 'Filename for filemtime() is unset' );
245 + }
246 +
247 + $label = "filemtime( '$filename' )";
248 +
249 + $filemtime_result = static::throw_on_warnings(
250 + function () use ( $filename ) {
251 + return filemtime( $filename );
252 + },
253 + $label
254 + );
255 +
256 + if ( false === $filemtime_result ) {
257 + throw new Exception( "Unable to $label" );
258 + }
259 +
260 + return $filemtime_result;
261 + }
262 +
263 + /**
264 + * Tell whether the filename is a directory (follow symlinks), throw on warnings / errors.
265 + *
266 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.is-dir
267 + * @see https://www.php.net/manual/en/function.is-dir.php
268 + *
269 + * @param string $filename Path to the file.
270 + *
271 + * @return bool True if the filename (or the symlink's target) exists and is a directory, false otherwise.
272 + * @throws Exception On invalid parameters, if is_dir() has thrown warnings, or has failed.
273 + */
274 + public static function t_is_dir( $filename ) {
275 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
276 + if ( ! $filename ) {
277 + throw new Exception( 'Filename for is_dir() is unset' );
278 + }
279 +
280 + return static::throw_on_warnings(
281 + function () use ( $filename ) {
282 + return is_dir( $filename );
283 + },
284 + "is_dir( '$filename' )"
285 + );
286 + }
287 +
288 + /**
289 + * Make a directory, throw on warnings / errors.
290 + *
291 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.mkdir
292 + * @see https://www.php.net/manual/en/function.mkdir.php
293 + *
294 + * @param string $directory Directory path.
295 + * @param int $permissions Permissions of the newly created directory.
296 + * @param bool $recursive If true, then any parent directories to the directory specified will also be created,
297 + * with the same permissions.
298 + *
299 + * @return void
300 + * @throws Exception On invalid parameters, if mkdir() has thrown warnings, or has failed.
301 + */
302 + public static function t_mkdir( $directory, $permissions = 0777, $recursive = false ) {
303 + // PHP 5.x won't complain about permissions being null, so let's do it ourselves.
304 + if ( $permissions === null ) {
305 + throw new Exception( 'Permissions for mkdir() are unset' );
306 + }
307 +
308 + $label = "mkdir( '$directory', 0" . decoct( $permissions ) . ', ' . ( $recursive ? 'true' : 'false' ) . ' )';
309 +
310 + $mkdir_result = static::throw_on_warnings(
311 + function () use ( $directory, $permissions, $recursive ) {
312 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir
313 + return mkdir( $directory, $permissions, $recursive );
314 + },
315 + $label
316 + );
317 +
318 + if ( false === $mkdir_result ) {
319 + throw new Exception( "Unable to $label" );
320 + }
321 + }
322 +
323 + /**
324 + * List files and directories inside the specified path, throw on warnings / errors.
325 + *
326 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.scandir
327 + * @see https://www.php.net/manual/en/function.scandir.php
328 + *
329 + * @param string $directory Directory that will be scanned.
330 + *
331 + * @return string[] An array of filenames.
332 + * @throws Exception If scandir() has thrown warnings, or has failed.
333 + */
334 + public static function t_scandir( $directory ) {
335 +
336 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
337 + if ( ! $directory ) {
338 + throw new Exception( 'Directory for scandir() is unset' );
339 + }
340 +
341 + $label = "scandir( '$directory' )";
342 +
343 + $scandir_result = static::throw_on_warnings(
344 + function () use ( $directory ) {
345 + return scandir( $directory );
346 + },
347 + $label
348 + );
349 +
350 + if ( false === $scandir_result ) {
351 + throw new Exception( "Unable to $label" );
352 + }
353 +
354 + return $scandir_result;
355 + }
356 +
357 + /**
358 + * Remove a directory, throw on warnings / errors.
359 + *
360 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.rmdir
361 + * @see https://www.php.net/manual/en/function.rmdir.php
362 + *
363 + * @param string $directory Directory path.
364 + *
365 + * @return void
366 + * @throws Exception On invalid parameters, if rmdir() has thrown warnings, or has failed.
367 + */
368 + public static function t_rmdir( $directory ) {
369 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
370 + if ( ! $directory ) {
371 + throw new Exception( 'Directory for mkdir() is unset' );
372 + }
373 +
374 + $label = "rmdir( '$directory' )";
375 +
376 + $rmdir_result = static::throw_on_warnings(
377 + function () use ( $directory ) {
378 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir
379 + return rmdir( $directory );
380 + },
381 + $label
382 + );
383 +
384 + if ( false === $rmdir_result ) {
385 + throw new Exception( "Unable to $label" );
386 + }
387 + }
388 +
389 + /**
390 + * Delete a file, throw on warnings / errors.
391 + *
392 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.unlink
393 + * @see https://www.php.net/manual/en/function.unlink.php
394 + *
395 + * @param string $filename Path to the file.
396 + *
397 + * @return void
398 + * @throws Exception If unlink() has thrown warnings, or has failed.
399 + */
400 + public static function t_unlink( $filename ) {
401 +
402 + $label = "unlink( '$filename' )";
403 +
404 + $unlink_result = static::throw_on_warnings(
405 + function () use ( $filename ) {
406 + // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink
407 + return unlink( $filename );
408 + },
409 + $label
410 + );
411 +
412 + if ( false === $unlink_result ) {
413 + throw new Exception( "Unable to $label" );
414 + }
415 + }
416 +
417 + /**
418 + * Write data to a file, throw on warnings / errors.
419 + *
420 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.file-put-contents
421 + * @see https://www.php.net/manual/en/function.file-put-contents.php
422 + *
423 + * @param string $filename Path to the file where to write the data.
424 + * @param string $data The data to write.
425 + *
426 + * @return void
427 + * @throws Exception If file_put_contents() has thrown warnings, has failed, or if it didn't write all the bytes.
428 + */
429 + public static function t_file_put_contents( $filename, $data ) {
430 +
431 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
432 + if ( ! $filename ) {
433 + throw new Exception( 'Filename for f_p_c() is unset' );
434 + }
435 + if ( $data === null ) {
436 + throw new Exception( 'Data to write is null' );
437 + }
438 +
439 + $data_length = strlen( $data );
440 +
441 + // Weird label is intentional, otherwise security scanners find this label suspicious.
442 + $label = "f_p_c( '$filename', $data_length bytes of data )";
443 +
444 + $number_of_bytes_written = static::throw_on_warnings(
445 + function () use ( $filename, $data ) {
446 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents
447 + return file_put_contents( $filename, $data );
448 + },
449 + $label
450 + );
451 +
452 + if ( false === $number_of_bytes_written ) {
453 + throw new Exception( "Unable to $label" );
454 + }
455 +
456 + if ( $number_of_bytes_written !== $data_length ) {
457 + throw new Exception(
458 + "$label was expected to write $data_length bytes, but wrote $number_of_bytes_written bytes"
459 + );
460 + }
461 + }
462 +
463 + /**
464 + * Read entire file into a string, throw on warnings / errors.
465 + *
466 + * @see https://php-legacy-docs.zend.com/manual/php5/en/function.file-get-contents
467 + * @see https://www.php.net/manual/en/function.file-get-contents.php
468 + *
469 + * @param string $filename Name of the file to read.
470 + *
471 + * @return string The read data.
472 + * @throws Exception If file_get_contents() has thrown warnings, or has failed.
473 + */
474 + public static function t_file_get_contents( $filename ) {
475 +
476 + // PHP 5.x won't complain about parameter being unset, so let's do it ourselves.
477 + if ( ! $filename ) {
478 + throw new Exception( 'Filename for f_g_c() is unset' );
479 + }
480 +
481 + // Weird label is intentional, otherwise security scanners find this label suspicious.
482 + $label = "f_g_c( '$filename' )";
483 +
484 + $fgc_result = static::throw_on_warnings(
485 + function () use ( $filename ) {
486 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
487 + return file_get_contents( $filename );
488 + },
489 + $label
490 + );
491 +
492 + if ( false === $fgc_result ) {
493 + throw new Exception( "Unable to $label" );
494 + }
495 +
496 + return $fgc_result;
497 + }
498 +}