View file File name : class-throw-on-errors.php Content :<?php // phpcs:disable Squiz.Commenting.FileComment.Missing // phpcs:disable WordPress.PHP.DevelopmentFunctions.prevent_path_disclosure_error_reporting // phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.runtime_configuration_error_reporting // phpcs:disable WordPress.PHP.IniSet.display_errors_Disallowed // After changing this file, consider increasing the version number ("VXXX") in all the files using this namespace, in // order to ensure that the specific version of this file always get loaded. Otherwise, Jetpack autoloader might decide // to load an older/newer version of the class (if, for example, both the standalone and bundled versions of the plugin // are installed, or in some other cases). namespace Automattic\Jetpack\Backup\V0004; use Exception; use Throwable; /** * Wrappers for functions which throw an exception on errors and warnings instead of silently continuing operation. * * PHP is pretty lax with error reporting when doing I/O operations, e.g. a typical I/O helper function returns false, * null, and/or emits a warning, but the whole PHP application continues operation. It's for the caller of the I/O * helper function to test the returned result of the function, and notice + act upon I/O errors. * * We really want to know about each and every I/O error. Therefore, this class provides wrappers for some common * (mostly) I/O operations that throw an exception on errors instead of just returning false, null, or something else. * This wrapper class treats warnings as errors too. * * Given that static method names are similar to the ones used by PHP, they're prefixed with "t_" to not erroneously * trigger various security scanners. */ class Throw_On_Errors { /** * Execute a callable, throw an exception (together with a descriptive label) on PHP warnings / errors. * * @param callable $callable Callable to execute. * @param string $label Label to add to the thrown exception to clarify what was attempted. * * @return mixed Callable's return value, if any. * @throws Exception On warnings thrown by the callable. * @noinspection PhpUnusedParameterInspection */ private static function throw_on_warnings( $callable, $label ) { $old_error_reporting = error_reporting( - 1 ); $old_display_errors = ini_set( 'display_errors', 'stderr' ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler set_error_handler( /** * Temporary error handler. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.set-error-handler * @see https://www.php.net/manual/en/function.set-error-handler.php * * @param int $errno Level of the error raised. * @param string $errstr Error message. * @param string|null $errfile Filename that the error was raised in. * @param int|null $errline Line number where the error was raised. * @param array|null $errcontext Deprecated, unused. * * @return never * @throws Exception */ // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable function ( $errno, $errstr, $errfile = null, $errline = null, $errcontext = null ) { throw new Exception( "$errstr (file: $errfile; line: $errline)" ); } ); $result = null; $error_message = null; try { $result = $callable(); } catch ( Throwable $throwable ) { $error_message = $throwable->getMessage(); } restore_error_handler(); ini_set( 'display_errors', $old_display_errors ); error_reporting( $old_error_reporting ); if ( $error_message !== null ) { throw new Exception( "$label failed: $error_message" ); } return $result; } /** * Return canonicalized absolute pathname, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.realpath * @see https://www.php.net/manual/en/function.realpath.php * * @param string $path Path being checked. * * @return string Canonicalized absolute pathname * @throws Exception On invalid parameters, or if realpath() has returned false or thrown warnings. */ public static function t_realpath( $path ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $path ) { throw new Exception( 'Filename for realpath() is unset' ); } $label = "realpath( '$path' )"; $realpath_result = static::throw_on_warnings( function () use ( $path ) { return realpath( $path ); }, $label ); if ( false === $realpath_result ) { throw new Exception( "Unable to $label" ); } return $realpath_result; } /** * Check whether a file or directory exists, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.file-exists * @see https://www.php.net/manual/en/function.file-exists.php * * @param string $filename Path to the file or directory. * * @return bool True if the file or directory specified by filename exists; false otherwise. * @throws Exception On invalid parameters, or if file_exists() has thrown warnings. */ public static function t_file_exists( $filename ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $filename ) { throw new Exception( 'Filename for file_exists() is unset' ); } return static::throw_on_warnings( function () use ( $filename ) { return file_exists( $filename ); }, "file_exists( '$filename' )" ); } /** * Tell whether the filename (or a directory) is readable, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.is-readable * @see https://www.php.net/manual/en/function.is-readable.php * * @param string $filename Filename (or directory) to check. * * @return bool True if the filename (or a directory) exists and is readable, false otherwise. * @throws Exception On invalid parameters, or if is_readable() has thrown warnings. */ public static function t_is_readable( $filename ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $filename ) { throw new Exception( 'Filename for is_readable() is unset' ); } return static::throw_on_warnings( function () use ( $filename ) { return is_readable( $filename ); }, "is_readable( '$filename' )" ); } /** * Tell whether the filename (or a directory) is writable, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.is-writable * @see https://www.php.net/manual/en/function.is-writable.php * * @param string $filename Filename (or directory) to check. * * @return bool True if the filename (or a directory) exists and is writable, false otherwise. * @throws Exception On invalid parameters, or if is_writable() has thrown warnings. */ public static function t_is_writable( $filename ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $filename ) { throw new Exception( 'Filename for is_writable() is unset' ); } return static::throw_on_warnings( function () use ( $filename ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable return is_writable( $filename ); }, "is_writable( '$filename' )" ); } /** * Get file size, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.filesize * @see https://www.php.net/manual/en/function.filesize.php * * @param string $filename Path to the file. * * @return int Size of the file in bytes * @throws Exception On invalid parameters, or if filesize() has thrown warnings. */ public static function t_filesize( $filename ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $filename ) { throw new Exception( 'Filename for filesize() is unset' ); } $label = "filesize( '$filename' )"; $filesize_result = static::throw_on_warnings( function () use ( $filename ) { return filesize( $filename ); }, $label ); if ( false === $filesize_result ) { throw new Exception( "Unable to $label" ); } return $filesize_result; } /** * Get file modification time, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.filemtime * @see https://www.php.net/manual/en/function.filemtime.php * * @param string $filename Path to the file. * * @return int The time the file was last modified * @throws Exception On invalid parameters, or if filemtime() has thrown warnings. */ public static function t_filemtime( $filename ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $filename ) { throw new Exception( 'Filename for filemtime() is unset' ); } $label = "filemtime( '$filename' )"; $filemtime_result = static::throw_on_warnings( function () use ( $filename ) { return filemtime( $filename ); }, $label ); if ( false === $filemtime_result ) { throw new Exception( "Unable to $label" ); } return $filemtime_result; } /** * Tell whether the filename is a directory (follow symlinks), throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.is-dir * @see https://www.php.net/manual/en/function.is-dir.php * * @param string $filename Path to the file. * * @return bool True if the filename (or the symlink's target) exists and is a directory, false otherwise. * @throws Exception On invalid parameters, if is_dir() has thrown warnings, or has failed. */ public static function t_is_dir( $filename ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $filename ) { throw new Exception( 'Filename for is_dir() is unset' ); } return static::throw_on_warnings( function () use ( $filename ) { return is_dir( $filename ); }, "is_dir( '$filename' )" ); } /** * Make a directory, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.mkdir * @see https://www.php.net/manual/en/function.mkdir.php * * @param string $directory Directory path. * @param int $permissions Permissions of the newly created directory. * @param bool $recursive If true, then any parent directories to the directory specified will also be created, * with the same permissions. * * @return void * @throws Exception On invalid parameters, if mkdir() has thrown warnings, or has failed. */ public static function t_mkdir( $directory, $permissions = 0777, $recursive = false ) { // PHP 5.x won't complain about permissions being null, so let's do it ourselves. if ( $permissions === null ) { throw new Exception( 'Permissions for mkdir() are unset' ); } $label = "mkdir( '$directory', 0" . decoct( $permissions ) . ', ' . ( $recursive ? 'true' : 'false' ) . ' )'; $mkdir_result = static::throw_on_warnings( function () use ( $directory, $permissions, $recursive ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_mkdir return mkdir( $directory, $permissions, $recursive ); }, $label ); if ( false === $mkdir_result ) { throw new Exception( "Unable to $label" ); } } /** * List files and directories inside the specified path, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.scandir * @see https://www.php.net/manual/en/function.scandir.php * * @param string $directory Directory that will be scanned. * * @return string An array of filenames. * @throws Exception If scandir() has thrown warnings, or has failed. */ public static function t_scandir( $directory ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $directory ) { throw new Exception( 'Directory for scandir() is unset' ); } $label = "scandir( '$directory' )"; $scandir_result = static::throw_on_warnings( function () use ( $directory ) { return scandir( $directory ); }, $label ); if ( false === $scandir_result ) { throw new Exception( "Unable to $label" ); } return $scandir_result; } /** * Remove a directory, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.rmdir * @see https://www.php.net/manual/en/function.rmdir.php * * @param string $directory Directory path. * * @return void * @throws Exception On invalid parameters, if rmdir() has thrown warnings, or has failed. */ public static function t_rmdir( $directory ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $directory ) { throw new Exception( 'Directory for mkdir() is unset' ); } $label = "rmdir( '$directory' )"; $rmdir_result = static::throw_on_warnings( function () use ( $directory ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_rmdir return rmdir( $directory ); }, $label ); if ( false === $rmdir_result ) { throw new Exception( "Unable to $label" ); } } /** * Delete a file, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.unlink * @see https://www.php.net/manual/en/function.unlink.php * * @param string $filename Path to the file. * * @return void * @throws Exception If unlink() has thrown warnings, or has failed. */ public static function t_unlink( $filename ) { $label = "unlink( '$filename' )"; $unlink_result = static::throw_on_warnings( function () use ( $filename ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.unlink_unlink return unlink( $filename ); }, $label ); if ( false === $unlink_result ) { throw new Exception( "Unable to $label" ); } } /** * Write data to a file, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.file-put-contents * @see https://www.php.net/manual/en/function.file-put-contents.php * * @param string $filename Path to the file where to write the data. * @param string $data The data to write. * * @return void * @throws Exception If file_put_contents() has thrown warnings, has failed, or if it didn't write all the bytes. */ public static function t_file_put_contents( $filename, $data ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $filename ) { throw new Exception( 'Filename for f_p_c() is unset' ); } if ( $data === null ) { throw new Exception( 'Data to write is null' ); } $data_length = strlen( $data ); // Weird label is intentional, otherwise security scanners find this label suspicious. $label = "f_p_c( '$filename', $data_length bytes of data )"; $number_of_bytes_written = static::throw_on_warnings( function () use ( $filename, $data ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents return file_put_contents( $filename, $data ); }, $label ); if ( false === $number_of_bytes_written ) { throw new Exception( "Unable to $label" ); } if ( $number_of_bytes_written !== $data_length ) { throw new Exception( "$label was expected to write $data_length bytes, but wrote $number_of_bytes_written bytes" ); } } /** * Read entire file into a string, throw on warnings / errors. * * @see https://php-legacy-docs.zend.com/manual/php5/en/function.file-get-contents * @see https://www.php.net/manual/en/function.file-get-contents.php * * @param string $filename Name of the file to read. * * @return string The read data. * @throws Exception If file_get_contents() has thrown warnings, or has failed. */ public static function t_file_get_contents( $filename ) { // PHP 5.x won't complain about parameter being unset, so let's do it ourselves. if ( ! $filename ) { throw new Exception( 'Filename for f_g_c() is unset' ); } // Weird label is intentional, otherwise security scanners find this label suspicious. $label = "f_g_c( '$filename' )"; $fgc_result = static::throw_on_warnings( function () use ( $filename ) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents return file_get_contents( $filename ); }, $label ); if ( false === $fgc_result ) { throw new Exception( "Unable to $label" ); } return $fgc_result; } }