wp/wp-admin/includes/file.php
changeset 19 3d72ae0968f4
parent 18 be944660c56a
child 21 48c4eec2b7e6
--- a/wp/wp-admin/includes/file.php	Wed Sep 21 18:19:35 2022 +0200
+++ b/wp/wp-admin/includes/file.php	Tue Sep 27 16:37:53 2022 +0200
@@ -223,7 +223,7 @@
 	);
 
 	/**
-	 * Filters the list of file types allowed for editing in the plugin editor.
+	 * Filters the list of file types allowed for editing in the plugin file editor.
 	 *
 	 * @since 2.8.0
 	 * @since 4.9.0 Added the `$plugin` parameter.
@@ -282,12 +282,12 @@
 	);
 
 	/**
-	 * Filters the list of file types allowed for editing in the theme editor.
+	 * Filters the list of file types allowed for editing in the theme file editor.
 	 *
 	 * @since 4.4.0
 	 *
 	 * @param string[] $default_types An array of editable theme file extensions.
-	 * @param WP_Theme $theme         The current theme object.
+	 * @param WP_Theme $theme         The active theme object.
 	 */
 	$file_types = apply_filters( 'wp_theme_editor_filetypes', $default_types, $theme );
 
@@ -715,7 +715,7 @@
 			wp_die( __( 'Sorry, that file cannot be edited.' ) );
 
 			// case 2 :
-			// wp_die( __('Sorry, can’t call files with their real path.' ));
+			// wp_die( __('Sorry, cannot call files with their real path.' ));
 
 		case 3:
 			wp_die( __( 'Sorry, that file cannot be edited.' ) );
@@ -733,9 +733,16 @@
  *
  * @see wp_handle_upload_error
  *
- * @param string[]       $file      Reference to a single element of `$_FILES`.
- *                                  Call the function once for each uploaded file.
- * @param array|false    $overrides {
+ * @param array       $file      {
+ *     Reference to a single element from `$_FILES`. Call the function once for each uploaded file.
+ *
+ *     @type string $name     The original name of the file on the client machine.
+ *     @type string $type     The mime type of the file, if the browser provided this information.
+ *     @type string $tmp_name The temporary filename of the file in which the uploaded file was stored on the server.
+ *     @type int    $size     The size, in bytes, of the uploaded file.
+ *     @type int    $error    The error code associated with this file upload.
+ * }
+ * @param array|false $overrides {
  *     An array of override parameters for this file, or boolean false if none are provided.
  *
  *     @type callable $upload_error_handler     Function to call when there is an error during the upload process.
@@ -749,11 +756,17 @@
  *     @type bool     $test_type                Whether to test that the mime type of the file is as expected.
  *     @type string[] $mimes                    Array of allowed mime types keyed by their file extension regex.
  * }
- * @param string         $time      Time formatted in 'yyyy/mm'.
- * @param string         $action    Expected value for `$_POST['action']`.
- * @return string[] On success, returns an associative array of file attributes.
- *                  On failure, returns `$overrides['upload_error_handler']( &$file, $message )`
- *                  or `array( 'error' => $message )`.
+ * @param string      $time      Time formatted in 'yyyy/mm'.
+ * @param string      $action    Expected value for `$_POST['action']`.
+ * @return array {
+ *     On success, returns an associative array of file attributes.
+ *     On failure, returns `$overrides['upload_error_handler']( &$file, $message )`
+ *     or `array( 'error' => $message )`.
+ *
+ *     @type string $file Filename of the newly-uploaded file.
+ *     @type string $url  URL of the newly-uploaded file.
+ *     @type string $type Mime type of the newly-uploaded file.
+ * }
  */
 function _wp_handle_upload( &$file, $overrides, $time, $action ) {
 	// The default error handler.
@@ -776,7 +789,15 @@
 	 * @since 2.9.0 as 'wp_handle_upload_prefilter'.
 	 * @since 4.0.0 Converted to a dynamic hook with `$action`.
 	 *
-	 * @param string[] $file An array of data for the file. Reference to a single element of `$_FILES`.
+	 * @param array $file {
+	 *     Reference to a single element from `$_FILES`.
+	 *
+	 *     @type string $name     The original name of the file on the client machine.
+	 *     @type string $type     The mime type of the file, if the browser provided this information.
+	 *     @type string $tmp_name The temporary filename of the file in which the uploaded file was stored on the server.
+	 *     @type int    $size     The size, in bytes, of the uploaded file.
+	 *     @type int    $error    The error code associated with this file upload.
+	 * }
 	 */
 	$file = apply_filters( "{$action}_prefilter", $file );
 
@@ -794,7 +815,15 @@
 	 *
 	 * @param array|false $overrides An array of override parameters for this file. Boolean false if none are
 	 *                               provided. @see _wp_handle_upload().
-	 * @param string[]    $file      An array of data for the file. Reference to a single element of `$_FILES`.
+	 * @param array       $file      {
+	 *     Reference to a single element from `$_FILES`.
+	 *
+	 *     @type string $name     The original name of the file on the client machine.
+	 *     @type string $type     The mime type of the file, if the browser provided this information.
+	 *     @type string $tmp_name The temporary filename of the file in which the uploaded file was stored on the server.
+	 *     @type int    $size     The size, in bytes, of the uploaded file.
+	 *     @type int    $error    The error code associated with this file upload.
+	 * }
 	 */
 	$overrides = apply_filters( "{$action}_overrides", $overrides, $file );
 
@@ -902,7 +931,7 @@
 		}
 
 		if ( ( ! $type || ! $ext ) && ! current_user_can( 'unfiltered_upload' ) ) {
-			return call_user_func_array( $upload_error_handler, array( &$file, __( 'Sorry, this file type is not permitted for security reasons.' ) ) );
+			return call_user_func_array( $upload_error_handler, array( &$file, __( 'Sorry, you are not allowed to upload this file type.' ) ) );
 		}
 
 		if ( ! $type ) {
@@ -935,7 +964,15 @@
 	 * @since 4.9.0
 	 *
 	 * @param mixed    $move_new_file If null (default) move the file after the upload.
-	 * @param string[] $file          An array of data for a single file.
+	 * @param array    $file          {
+	 *     Reference to a single element from `$_FILES`.
+	 *
+	 *     @type string $name     The original name of the file on the client machine.
+	 *     @type string $type     The mime type of the file, if the browser provided this information.
+	 *     @type string $tmp_name The temporary filename of the file in which the uploaded file was stored on the server.
+	 *     @type int    $size     The size, in bytes, of the uploaded file.
+	 *     @type int    $error    The error code associated with this file upload.
+	 * }
 	 * @param string   $new_file      Filename of the newly-uploaded file.
 	 * @param string   $type          Mime type of the newly-uploaded file.
 	 */
@@ -1017,12 +1054,12 @@
  *
  * @param array       $file      Reference to a single element of `$_FILES`.
  *                               Call the function once for each uploaded file.
+ *                               See _wp_handle_upload() for accepted values.
  * @param array|false $overrides Optional. An associative array of names => values
  *                               to override default variables. Default false.
+ *                               See _wp_handle_upload() for accepted values.
  * @param string      $time      Optional. Time formatted in 'yyyy/mm'. Default null.
- * @return array On success, returns an associative array of file attributes.
- *               On failure, returns `$overrides['upload_error_handler']( &$file, $message )`
- *               or `array( 'error' => $message )`.
+ * @return array See _wp_handle_upload() for return value.
  */
 function wp_handle_upload( &$file, $overrides = false, $time = null ) {
 	/*
@@ -1048,12 +1085,12 @@
  *
  * @param array       $file      Reference to a single element of `$_FILES`.
  *                               Call the function once for each uploaded file.
+ *                               See _wp_handle_upload() for accepted values.
  * @param array|false $overrides Optional. An associative array of names => values
  *                               to override default variables. Default false.
+ *                               See _wp_handle_upload() for accepted values.
  * @param string      $time      Optional. Time formatted in 'yyyy/mm'. Default null.
- * @return array On success, returns an associative array of file attributes.
- *               On failure, returns `$overrides['upload_error_handler']( &$file, $message )`
- *               or `array( 'error' => $message )`.
+ * @return array See _wp_handle_upload() for return value.
  */
 function wp_handle_sideload( &$file, $overrides = false, $time = null ) {
 	/*
@@ -1075,6 +1112,7 @@
  *
  * @since 2.5.0
  * @since 5.2.0 Signature Verification with SoftFail was added.
+ * @since 5.9.0 Support for Content-Disposition filename was added.
  *
  * @param string $url                    The URL of the file to download.
  * @param int    $timeout                The timeout for the request to download the file.
@@ -1089,7 +1127,11 @@
 		return new WP_Error( 'http_no_url', __( 'Invalid URL Provided.' ) );
 	}
 
-	$url_filename = basename( parse_url( $url, PHP_URL_PATH ) );
+	$url_path     = parse_url( $url, PHP_URL_PATH );
+	$url_filename = '';
+	if ( is_string( $url_path ) && '' !== $url_path ) {
+		$url_filename = basename( $url_path );
+	}
 
 	$tmpfname = wp_tempnam( $url_filename );
 	if ( ! $tmpfname ) {
@@ -1141,6 +1183,33 @@
 		return new WP_Error( 'http_404', trim( wp_remote_retrieve_response_message( $response ) ), $data );
 	}
 
+	$content_disposition = wp_remote_retrieve_header( $response, 'content-disposition' );
+
+	if ( $content_disposition ) {
+		$content_disposition = strtolower( $content_disposition );
+
+		if ( 0 === strpos( $content_disposition, 'attachment; filename=' ) ) {
+			$tmpfname_disposition = sanitize_file_name( substr( $content_disposition, 21 ) );
+		} else {
+			$tmpfname_disposition = '';
+		}
+
+		// Potential file name must be valid string.
+		if ( $tmpfname_disposition && is_string( $tmpfname_disposition )
+			&& ( 0 === validate_file( $tmpfname_disposition ) )
+		) {
+			$tmpfname_disposition = dirname( $tmpfname ) . '/' . $tmpfname_disposition;
+
+			if ( rename( $tmpfname, $tmpfname_disposition ) ) {
+				$tmpfname = $tmpfname_disposition;
+			}
+
+			if ( ( $tmpfname !== $tmpfname_disposition ) && file_exists( $tmpfname_disposition ) ) {
+				unlink( $tmpfname_disposition );
+			}
+		}
+	}
+
 	$content_md5 = wp_remote_retrieve_header( $response, 'content-md5' );
 
 	if ( $content_md5 ) {
@@ -1175,9 +1244,8 @@
 			// WordPress.org stores signatures at $package_url.sig.
 
 			$signature_url = false;
-			$url_path      = parse_url( $url, PHP_URL_PATH );
 
-			if ( '.zip' === substr( $url_path, -4 ) || '.tar.gz' === substr( $url_path, -7 ) ) {
+			if ( is_string( $url_path ) && ( '.zip' === substr( $url_path, -4 ) || '.tar.gz' === substr( $url_path, -7 ) ) ) {
 				$signature_url = str_replace( $url_path, $url_path . '.sig', $url );
 			}
 
@@ -1206,7 +1274,7 @@
 		}
 
 		// Perform the checks.
-		$signature_verification = verify_file_signature( $tmpfname, $signature, basename( parse_url( $url, PHP_URL_PATH ) ) );
+		$signature_verification = verify_file_signature( $tmpfname, $signature, $url_filename );
 	}
 
 	if ( is_wp_error( $signature_verification ) ) {
@@ -1318,7 +1386,6 @@
 			),
 			array(
 				'php'    => phpversion(),
-				// phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
 				'sodium' => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
 			)
 		);
@@ -1330,7 +1397,10 @@
 
 		// Allow for an old version of Sodium_Compat being loaded before the bundled WordPress one.
 		if ( method_exists( 'ParagonIE_Sodium_Compat', 'runtime_speed_test' ) ) {
-			// Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode, as that's what WordPress utilises during signing verifications.
+			/*
+			 * Run `ParagonIE_Sodium_Compat::runtime_speed_test()` in optimized integer mode,
+			 * as that's what WordPress utilizes during signing verifications.
+			 */
 			// phpcs:disable WordPress.NamingConventions.ValidVariableName
 			$old_fastMult                      = ParagonIE_Sodium_Compat::$fastMult;
 			ParagonIE_Sodium_Compat::$fastMult = true;
@@ -1351,7 +1421,6 @@
 				),
 				array(
 					'php'                => phpversion(),
-					// phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
 					'sodium'             => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
 					'polyfill_is_fast'   => false,
 					'max_execution_time' => ini_get( 'max_execution_time' ),
@@ -1425,7 +1494,6 @@
 			'skipped_key' => $skipped_key,
 			'skipped_sig' => $skipped_signature,
 			'php'         => phpversion(),
-			// phpcs:ignore PHPCompatibility.Constants.NewConstants.sodium_library_versionFound
 			'sodium'      => defined( 'SODIUM_LIBRARY_VERSION' ) ? SODIUM_LIBRARY_VERSION : ( defined( 'ParagonIE_Sodium_Compat::VERSION_STRING' ) ? ParagonIE_Sodium_Compat::VERSION_STRING : false ),
 		)
 	);
@@ -1598,7 +1666,7 @@
 	 * Require we have enough space to unzip the file and copy its contents, with a 10% buffer.
 	 */
 	if ( wp_doing_cron() ) {
-		$available_space = @disk_free_space( WP_CONTENT_DIR );
+		$available_space = function_exists( 'disk_free_space' ) ? @disk_free_space( WP_CONTENT_DIR ) : false;
 
 		if ( $available_space && ( $uncompressed_size * 2.1 ) > $available_space ) {
 			return new WP_Error(
@@ -1739,7 +1807,7 @@
 	 * Require we have enough space to unzip the file and copy its contents, with a 10% buffer.
 	 */
 	if ( wp_doing_cron() ) {
-		$available_space = @disk_free_space( WP_CONTENT_DIR );
+		$available_space = function_exists( 'disk_free_space' ) ? @disk_free_space( WP_CONTENT_DIR ) : false;
 
 		if ( $available_space && ( $uncompressed_size * 2.1 ) > $available_space ) {
 			return new WP_Error(
@@ -2078,7 +2146,7 @@
  * @since 2.5.0
  * @since 4.6.0 The `$context` parameter default changed from `false` to an empty string.
  *
- * @global string $pagenow
+ * @global string $pagenow The filename of the current screen.
  *
  * @param string        $form_post                    The URL to post the form to.
  * @param string        $type                         Optional. Chosen type of filesystem. Default empty.