_wp_handle_upload

Handle PHP uploads in WordPress, sanitizing file names, checking extensions for mime type, and moving the file to the appropriate directory within the uploads directory.

Description

(array) _wp_handle_upload( (array) &$file, (array|false) $overrides, (string) $time, (string) $action ); 

Returns (array)

On success, returns an associative array of file attributes. On failure, returns $overrides['upload_error_handler'](&$file, $message ) or array( 'error'=>$message ).

Parameters (4)

0. $file (array) => &$file
Reference to a single element of $_FILES. Call the function once for each uploaded file.
1. $overrides (array|false)
An associative array of names => values to override default variables. Default false.
2. $time (string)
Time formatted in yyyy/mm..
3. $action (string)
Expected value for $_POST['action'].

Usage

  1. if ( !function_exists( '_wp_handle_upload' ) ) { 
  2. require_once ABSPATH . '/wp-admin/includes/file.php'; 
  3.  
  4. // Reference to a single element of $_FILES. Call the function once for each uploaded file. 
  5. $file = array(); 
  6.  
  7. // An associative array of names => values to override default variables. Default false. 
  8. $overrides = null; 
  9.  
  10. // Time formatted in 'yyyy/mm'. 
  11. $time = ''; 
  12.  
  13. // Expected value for $_POST['action']. 
  14. $action = ''; 
  15.  
  16. // NOTICE! Understand what this does before running. 
  17. $result = _wp_handle_upload($file, $overrides, $time, $action); 
  18.  

Defined (2)

The function is defined in the following location(s).

/wp-admin/includes/file.php  
  1. function _wp_handle_upload( &$file, $overrides, $time, $action ) { 
  2. // The defaulterrorhandler. 
  3. if ( ! function_exists( 'wp_handle_upload_error' ) ) { 
  4. function wp_handle_upload_error( &$file, $message ) { 
  5. return array( error => $message ); 
  6.  
  7. /** 
  8. * Filters the data for a file before it is uploaded to WordPress. 
  9. * The dynamic portion of the hook name, `$action`, refers to the post action. 
  10. * @since 2.9.0 as 'wp_handle_upload_prefilter'. 
  11. * @since 4.0.0 Converted to a dynamic hook with `$action`. 
  12. * @param array $file An array of data for a single file. 
  13. */ 
  14. $file = apply_filters( "{$action}_prefilter", $file ); 
  15.  
  16. // You may define your own function and pass the name in $overrides['upload_error_handler'] 
  17. $upload_error_handler = 'wp_handle_upload_error'; 
  18. if ( isset( $overrides['upload_error_handler'] ) ) { 
  19. $upload_error_handler = $overrides['upload_error_handler']; 
  20.  
  21. // You may have had one or more 'wp_handle_upload_prefilter' functionserrorout the file. Handle that gracefully. 
  22. if ( isset( $file[error] ) && ! is_numeric( $file[error] ) && $file[error] ) { 
  23. return call_user_func_array( $upload_error_handler, array( &$file, $file[error] ) ); 
  24.  
  25. // Install user overrides. Did we mention that this voids your warranty? 
  26.  
  27. // You may define your own function and pass the name in $overrides['unique_filename_callback'] 
  28. $unique_filename_callback = null; 
  29. if ( isset( $overrides['unique_filename_callback'] ) ) { 
  30. $unique_filename_callback = $overrides['unique_filename_callback']; 
  31.  
  32. /** 
  33. * This may not have orignially been intended to be overrideable,  
  34. * but historically has been. 
  35. */ 
  36. if ( isset( $overrides['upload_error_strings'] ) ) { 
  37. $upload_error_strings = $overrides['upload_error_strings']; 
  38. } else { 
  39. // Courtesy of php.net, the strings that describe theerrorindicated in $_FILES[{form field}][error]. 
  40. $upload_error_strings = array( 
  41. false,  
  42. __( 'The uploaded file exceeds the upload_max_filesize directive in php.ini.' ),  
  43. __( 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.' ),  
  44. __( 'The uploaded file was only partially uploaded.' ),  
  45. __( 'No file was uploaded.' ),  
  46. '',  
  47. __( 'Missing a temporary folder.' ),  
  48. __( 'Failed to write file to disk.' ),  
  49. __( 'File upload stopped by extension.' ) 
  50. ); 
  51.  
  52. // All tests are on by default. Most can be turned off by $overrides[{test_name}] = false; 
  53. $test_form = isset( $overrides['test_form'] ) ? $overrides['test_form'] : true; 
  54. $test_size = isset( $overrides['test_size'] ) ? $overrides['test_size'] : true; 
  55.  
  56. // If you override this, you must provide $ext and $type!! 
  57. $test_type = isset( $overrides['test_type'] ) ? $overrides['test_type'] : true; 
  58. $mimes = isset( $overrides['mimes'] ) ? $overrides['mimes'] : false; 
  59.  
  60. // A correct form post will pass this test. 
  61. if ( $test_form && ( ! isset( $_POST['action'] ) || ( $_POST['action'] != $action ) ) ) { 
  62. return call_user_func_array( $upload_error_handler, array( &$file, __( 'Invalid form submission.' ) ) ); 
  63. // A successful upload will pass this test. It makes no sense to override this one. 
  64. if ( isset( $file[error] ) && $file[error] > 0 ) { 
  65. return call_user_func_array( $upload_error_handler, array( &$file, $upload_error_strings[ $file[error] ] ) ); 
  66.  
  67. $test_file_size = 'wp_handle_upload' === $action ? $file['size'] : filesize( $file['tmp_name'] ); 
  68. // A non-empty file will pass this test. 
  69. if ( $test_size && ! ( $test_file_size > 0 ) ) { 
  70. if ( is_multisite() ) { 
  71. $error_msg = __( 'File is empty. Please upload something more substantial.' ); 
  72. } else { 
  73. $error_msg = __( 'File is empty. Please upload something more substantial. Thiserrorcould also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.' ); 
  74. return call_user_func_array( $upload_error_handler, array( &$file, $error_msg ) ); 
  75.  
  76. // A properly uploaded file will pass this test. There should be no reason to override this one. 
  77. $test_uploaded_file = 'wp_handle_upload' === $action ? @ is_uploaded_file( $file['tmp_name'] ) : @ is_file( $file['tmp_name'] ); 
  78. if ( ! $test_uploaded_file ) { 
  79. return call_user_func_array( $upload_error_handler, array( &$file, __( 'Specified file failed upload test.' ) ) ); 
  80.  
  81. // A correct MIME type will pass this test. Override $mimes or use the upload_mimes filter. 
  82. if ( $test_type ) { 
  83. $wp_filetype = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'], $mimes ); 
  84. $ext = empty( $wp_filetype['ext'] ) ? '' : $wp_filetype['ext']; 
  85. $type = empty( $wp_filetype['type'] ) ? '' : $wp_filetype['type']; 
  86. $proper_filename = empty( $wp_filetype['proper_filename'] ) ? '' : $wp_filetype['proper_filename']; 
  87.  
  88. // Check to see if wp_check_filetype_and_ext() determined the filename was incorrect 
  89. if ( $proper_filename ) { 
  90. $file['name'] = $proper_filename; 
  91. if ( ( ! $type || !$ext ) && ! current_user_can( 'unfiltered_upload' ) ) { 
  92. return call_user_func_array( $upload_error_handler, array( &$file, __( 'Sorry, this file type is not permitted for security reasons.' ) ) ); 
  93. if ( ! $type ) { 
  94. $type = $file['type']; 
  95. } else { 
  96. $type = ''; 
  97.  
  98. /** 
  99. * A writable uploads dir will pass this test. Again, there's no point 
  100. * overriding this one. 
  101. */ 
  102. if ( ! ( ( $uploads = wp_upload_dir( $time ) ) && false === $uploads[error] ) ) { 
  103. return call_user_func_array( $upload_error_handler, array( &$file, $uploads[error] ) ); 
  104.  
  105. $filename = wp_unique_filename( $uploads['path'], $file['name'], $unique_filename_callback ); 
  106.  
  107. // Move the file to the uploads dir. 
  108. $new_file = $uploads['path'] . "/$filename"; 
  109. if ( 'wp_handle_upload' === $action ) { 
  110. $move_new_file = @ move_uploaded_file( $file['tmp_name'], $new_file ); 
  111. } else { 
  112. // use copy and unlink because rename breaks streams. 
  113. $move_new_file = @ copy( $file['tmp_name'], $new_file ); 
  114. unlink( $file['tmp_name'] ); 
  115.  
  116. if ( false === $move_new_file ) { 
  117. if ( 0 === strpos( $uploads['basedir'], ABSPATH ) ) { 
  118. $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir']; 
  119. } else { 
  120. $error_path = basename( $uploads['basedir'] ) . $uploads['subdir']; 
  121. return $upload_error_handler( $file, sprintf( __('The uploaded file could not be moved to %s.' ), $error_path ) ); 
  122.  
  123. // Set correct file permissions. 
  124. $stat = stat( dirname( $new_file )); 
  125. $perms = $stat['mode'] & 0000666; 
  126. @ chmod( $new_file, $perms ); 
  127.  
  128. // Compute the URL. 
  129. $url = $uploads['url'] . "/$filename"; 
  130.  
  131. if ( is_multisite() ) { 
  132. delete_transient( 'dirsize_cache' ); 
  133.  
  134. /** 
  135. * Filters the data array for the uploaded file. 
  136. * @since 2.1.0 
  137. * @param array $upload { 
  138. * Array of upload data. 
  139. * @type string $file Filename of the newly-uploaded file. 
  140. * @type string $url URL of the uploaded file. 
  141. * @type string $type File type. 
  142. * } 
  143. * @param string $context The type of upload action. Values include 'upload' or 'sideload'. 
  144. */ 
  145. 'file' => $new_file,  
  146. 'url' => $url,  
  147. 'type' => $type 
  148. ), 'wp_handle_sideload' === $action ? 'sideload' : 'upload' ); 
  1. function wp_handle_upload( &$file, $overrides = false, $time = null ) { 
  2. /** 
  3. * $_POST['action'] must be set and its value must equal $overrides['action'] 
  4. * or this: 
  5. */ 
  6. $action = 'wp_handle_upload'; 
  7. if ( isset( $overrides['action'] ) ) { 
  8. $action = $overrides['action']; 
  9.  
  10. return _wp_handle_upload( $file, $overrides, $time, $action );