PluginProbe ʕ •ᴥ•ʔ
Contact Form 7 / 6.0.5
Contact Form 7 v6.0.5
6.1.6 5.0.2 5.0.3 5.0.4 5.0.5 5.1 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.2 5.2.1 5.2.2 5.3 5.3.1 5.3.2 5.4 5.4.1 5.4.2 5.5 5.5.1 5.5.2 5.5.3 5.5.4 5.5.5 5.5.6 5.5.6.1 5.6 5.6.1 5.6.2 5.6.3 5.6.4 5.7 5.7.1 5.7.2 5.7.3 5.7.4 5.7.5 5.7.5.1 5.7.6 5.7.7 5.8 5.8.1 5.8.2 5.8.3 5.8.4 5.8.5 5.8.6 5.8.7 5.9 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 6.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.0.6 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 trunk 1.1 1.10 1.10.0.1 1.10.1 1.2 1.3 1.3.1 1.3.2 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.5 1.6 1.6.1 1.7 1.7.1 1.7.2 1.7.4 1.7.5 1.7.6 1.7.6.1 1.7.7 1.7.7.1 1.7.8 1.8 1.8.0.1 1.8.0.2 1.8.0.3 1.8.0.4 1.8.1 1.8.1.1 1.9 1.9.1 1.9.2 1.9.2.1 1.9.2.2 1.9.3 1.9.4 1.9.5 1.9.5.1 2.0 2.0-beta 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1 2.1.1 2.1.2 2.2 2.2.1 2.3 2.3.1 2.4 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 3.0 3.0-beta 3.0.1 3.0.2 3.0.2.1 3.1 3.1.1 3.1.2 3.2 3.2.1 3.3 3.3.1 3.3.2 3.3.3 3.4 3.4.1 3.4.2 3.5 3.5.1 3.5.2 3.5.3 3.5.4 3.6 3.7 3.7.1 3.7.2 3.8 3.8.1 3.9 3.9-beta 3.9.1 3.9.2 3.9.3 4.0 4.0.1 4.0.2 4.0.3 4.1 4.1-beta 4.1.1 4.1.2 4.2 4.2-beta 4.2.1 4.2.2 4.3 4.3.1 4.4 4.4.1 4.4.2 4.5 4.5.1 4.6 4.6.1 4.7 4.8 4.8.1 4.9 4.9.1 4.9.2 5.0 5.0.1
contact-form-7 / includes / file.php
contact-form-7 / includes Last commit date
block-editor 1 year ago config-validator 1 year ago css 2 years ago js 1 year ago swv 1 year ago capabilities.php 7 years ago contact-form-functions.php 1 year ago contact-form-template.php 1 year ago contact-form.php 1 year ago controller.php 1 year ago file.php 1 year ago form-tag.php 1 year ago form-tags-manager.php 1 year ago formatting.php 1 year ago functions.php 1 year ago html-formatter.php 1 year ago integration.php 1 year ago l10n.php 1 year ago mail-tag.php 2 years ago mail.php 1 year ago pipe.php 1 year ago pocket-holder.php 3 years ago rest-api.php 1 year ago shortcodes.php 1 year ago special-mail-tags.php 1 year ago submission.php 1 year ago upgrade.php 2 years ago validation-functions.php 1 year ago validation.php 1 year ago
file.php
422 lines
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 $options Optional. Options to control behavior.
8 * @return array|WP_Error Array of file paths, or WP_Error if validation fails.
9 */
10 function wpcf7_unship_uploaded_file( $file, $options = '' ) {
11 $options = wp_parse_args( $options, array(
12 'required' => false,
13 'filetypes' => '',
14 'limit' => MB_IN_BYTES,
15 ) );
16
17 foreach ( array( 'name', 'size', 'tmp_name', 'error' ) as $key ) {
18 if ( ! isset( $file[$key] ) ) {
19 $file[$key] = array();
20 }
21 }
22
23 $names = wpcf7_array_flatten( $file['name'] );
24 $sizes = wpcf7_array_flatten( $file['size'] );
25 $tmp_names = wpcf7_array_flatten( $file['tmp_name'] );
26 $errors = wpcf7_array_flatten( $file['error'] );
27
28 foreach ( $errors as $error ) {
29 if ( ! empty( $error ) and UPLOAD_ERR_NO_FILE !== $error ) {
30 return new WP_Error( 'wpcf7_upload_failed_php_error',
31 wpcf7_get_message( 'upload_failed_php_error' )
32 );
33 }
34 }
35
36 if ( isset( $options['schema'] ) and isset( $options['name'] ) ) {
37 $context = array(
38 'file' => true,
39 'field' => $options['name'],
40 );
41
42 foreach ( $options['schema']->validate( $context ) as $result ) {
43 if ( is_wp_error( $result ) ) {
44 return $result;
45 }
46 }
47 }
48
49 // Move uploaded file to tmp dir
50 $uploads_dir = wpcf7_upload_tmp_dir();
51 $uploads_dir = wpcf7_maybe_add_random_dir( $uploads_dir );
52
53 $uploaded_files = array();
54
55 foreach ( $names as $key => $name ) {
56 $tmp_name = $tmp_names[$key];
57
58 if ( empty( $tmp_name ) or ! is_uploaded_file( $tmp_name ) ) {
59 continue;
60 }
61
62 $filename = $name;
63 $filename = wpcf7_canonicalize( $filename, array( 'strto' => 'as-is' ) );
64 $filename = wpcf7_antiscript_file_name( $filename );
65
66 $filename = apply_filters( 'wpcf7_upload_file_name',
67 $filename, $name, $options
68 );
69
70 $filename = wp_unique_filename( $uploads_dir, $filename );
71 $new_file = path_join( $uploads_dir, $filename );
72
73 if ( false === @move_uploaded_file( $tmp_name, $new_file ) ) {
74 return new WP_Error( 'wpcf7_upload_failed',
75 wpcf7_get_message( 'upload_failed' )
76 );
77 }
78
79 // Make sure the uploaded file is only readable for the owner process
80 chmod( $new_file, 0400 );
81
82 $uploaded_files[] = $new_file;
83 }
84
85 return $uploaded_files;
86 }
87
88
89 add_filter(
90 'wpcf7_messages',
91 'wpcf7_file_messages',
92 10, 1
93 );
94
95 /**
96 * A wpcf7_messages filter callback that adds messages for
97 * file-uploading fields.
98 */
99 function wpcf7_file_messages( $messages ) {
100 return array_merge( $messages, array(
101 'upload_failed' => array(
102 'description' => __( "Uploading a file fails for any reason", 'contact-form-7' ),
103 'default' => __( "There was an unknown error uploading the file.", 'contact-form-7' ),
104 ),
105
106 'upload_file_type_invalid' => array(
107 'description' => __( "Uploaded file is not allowed for file type", 'contact-form-7' ),
108 'default' => __( "You are not allowed to upload files of this type.", 'contact-form-7' ),
109 ),
110
111 'upload_file_too_large' => array(
112 'description' => __( "Uploaded file is too large", 'contact-form-7' ),
113 'default' => __( "The uploaded file is too large.", 'contact-form-7' ),
114 ),
115
116 'upload_failed_php_error' => array(
117 'description' => __( "Uploading a file fails for PHP error", 'contact-form-7' ),
118 'default' => __( "There was an error uploading the file.", 'contact-form-7' ),
119 ),
120 ) );
121 }
122
123
124 add_filter(
125 'wpcf7_form_enctype',
126 'wpcf7_file_form_enctype_filter',
127 10, 1
128 );
129
130 /**
131 * A wpcf7_form_enctype filter callback that sets the enctype attribute
132 * to multipart/form-data if the form has file-uploading fields.
133 */
134 function wpcf7_file_form_enctype_filter( $enctype ) {
135 $multipart = (bool) wpcf7_scan_form_tags( array(
136 'feature' => 'file-uploading',
137 ) );
138
139 if ( $multipart ) {
140 $enctype = 'multipart/form-data';
141 }
142
143 return $enctype;
144 }
145
146
147 /**
148 * Converts a MIME type string to an array of corresponding file extensions.
149 *
150 * @param string $mime MIME type.
151 * Wildcard (*) is available for the subtype part.
152 * @return array Corresponding file extensions.
153 */
154 function wpcf7_convert_mime_to_ext( $mime ) {
155 static $mime_types = array();
156
157 $mime_types = wp_get_mime_types();
158
159 $results = array();
160
161 if ( preg_match( '%^([a-z]+)/([*]|[a-z0-9.+-]+)$%i', $mime, $matches ) ) {
162 foreach ( $mime_types as $key => $val ) {
163 if ( '*' === $matches[2] and str_starts_with( $val, $matches[1] . '/' )
164 or $val === $matches[0] ) {
165 $results = array_merge( $results, explode( '|', $key ) );
166 }
167 }
168 }
169
170 $results = array_unique( $results );
171 $results = array_filter( $results );
172 $results = array_values( $results );
173
174 return $results;
175 }
176
177
178 /**
179 * Returns a formatted list of acceptable filetypes.
180 *
181 * @param string|array $types Optional. Array of filetypes.
182 * @param string $format Optional. Pre-defined format designator.
183 * @return string Formatted list of acceptable filetypes.
184 */
185 function wpcf7_acceptable_filetypes( $types = 'default', $format = 'regex' ) {
186 if ( 'default' === $types or empty( $types ) ) {
187 $types = array(
188 'audio/*',
189 'video/*',
190 'image/*',
191 );
192 } else {
193 $types = array_map(
194 static function ( $type ) {
195 if ( is_string( $type ) ) {
196 return preg_split( '/[\s|,]+/', strtolower( $type ) );
197 }
198 },
199 (array) $types
200 );
201
202 $types = wpcf7_array_flatten( $types );
203 $types = array_filter( array_unique( $types ) );
204 }
205
206 if ( 'attr' === $format or 'attribute' === $format ) {
207 $types = array_map(
208 static function ( $type ) {
209 if ( false === strpos( $type, '/' ) ) {
210 return sprintf( '.%s', trim( $type, '.' ) );
211 } elseif ( preg_match( '%^([a-z]+)/[*]$%i', $type, $matches ) ) {
212 if ( in_array( $matches[1], array( 'audio', 'video', 'image' ), true ) ) {
213 return $type;
214 } else {
215 return '';
216 }
217 } elseif ( wpcf7_convert_mime_to_ext( $type ) ) {
218 return $type;
219 }
220 },
221 $types
222 );
223
224 $types = array_filter( $types );
225
226 return implode( ',', $types );
227
228 } elseif ( 'regex' === $format ) {
229 $types = array_map(
230 static function ( $type ) {
231 if ( false === strpos( $type, '/' ) ) {
232 return preg_quote( trim( $type, '.' ) );
233 } elseif ( $type = wpcf7_convert_mime_to_ext( $type ) ) {
234 return $type;
235 }
236 },
237 $types
238 );
239
240 $types = wpcf7_array_flatten( $types );
241 $types = array_filter( array_unique( $types ) );
242
243 return implode( '|', $types );
244 }
245
246 return '';
247 }
248
249
250 add_action(
251 'wpcf7_init',
252 'wpcf7_init_uploads',
253 10, 0
254 );
255
256 /**
257 * Initializes the temporary directory for uploaded files.
258 */
259 function wpcf7_init_uploads() {
260 $dir = wpcf7_upload_tmp_dir();
261
262 if ( is_dir( $dir ) and is_writable( $dir ) ) {
263 $htaccess_file = path_join( $dir, '.htaccess' );
264
265 if ( file_exists( $htaccess_file ) ) {
266 list( $first_line_comment ) = (array) file(
267 $htaccess_file,
268 FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES
269 );
270
271 if ( '# Apache 2.4+' === $first_line_comment ) {
272 return;
273 }
274 }
275
276 if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
277 fwrite( $handle, "# Apache 2.4+\n" );
278 fwrite( $handle, "<IfModule authz_core_module>\n" );
279 fwrite( $handle, " Require all denied\n" );
280 fwrite( $handle, "</IfModule>\n" );
281 fwrite( $handle, "\n" );
282 fwrite( $handle, "# Apache 2.2\n" );
283 fwrite( $handle, "<IfModule !authz_core_module>\n" );
284 fwrite( $handle, " Deny from all\n" );
285 fwrite( $handle, "</IfModule>\n" );
286
287 fclose( $handle );
288 }
289 }
290 }
291
292
293 /**
294 * Creates a child directory with a randomly generated name.
295 *
296 * @param string $dir The parent directory path.
297 * @return string The child directory path if created, otherwise the parent.
298 */
299 function wpcf7_maybe_add_random_dir( $dir ) {
300 do {
301 $rand_max = mt_getrandmax();
302 $rand = zeroise( mt_rand( 0, $rand_max ), strlen( $rand_max ) );
303 $dir_new = path_join( $dir, $rand );
304 } while ( file_exists( $dir_new ) );
305
306 if ( wp_mkdir_p( $dir_new ) ) {
307 return $dir_new;
308 }
309
310 return $dir;
311 }
312
313
314 /**
315 * Returns the directory path for uploaded files.
316 *
317 * @return string Directory path.
318 */
319 function wpcf7_upload_tmp_dir() {
320 if ( defined( 'WPCF7_UPLOADS_TMP_DIR' ) ) {
321 $dir = path_join( WP_CONTENT_DIR, WPCF7_UPLOADS_TMP_DIR );
322 wp_mkdir_p( $dir );
323
324 if ( wpcf7_is_file_path_in_content_dir( $dir ) ) {
325 return $dir;
326 }
327 }
328
329 $dir = path_join( wpcf7_upload_dir( 'dir' ), 'wpcf7_uploads' );
330 wp_mkdir_p( $dir );
331 return $dir;
332 }
333
334
335 add_action(
336 'shutdown',
337 'wpcf7_cleanup_upload_files',
338 20, 0
339 );
340
341 /**
342 * Cleans up files in the temporary directory for uploaded files.
343 *
344 * @param int $seconds Files older than this are removed. Default 60.
345 * @param int $max Maximum number of files to be removed in a function call.
346 * Default 100.
347 */
348 function wpcf7_cleanup_upload_files( $seconds = 60, $max = 100 ) {
349 $dir = trailingslashit( wpcf7_upload_tmp_dir() );
350
351 if ( ! is_dir( $dir )
352 or ! is_readable( $dir )
353 or ! wp_is_writable( $dir ) ) {
354 return;
355 }
356
357 $seconds = absint( $seconds );
358 $max = absint( $max );
359 $count = 0;
360
361 if ( $handle = opendir( $dir ) ) {
362 while ( false !== ( $file = readdir( $handle ) ) ) {
363 if ( '.' === $file or '..' === $file or '.htaccess' === $file ) {
364 continue;
365 }
366
367 $mtime = @filemtime( path_join( $dir, $file ) );
368
369 if ( $mtime and time() < $mtime + $seconds ) { // less than $seconds old
370 continue;
371 }
372
373 wpcf7_rmdir_p( path_join( $dir, $file ) );
374 $count += 1;
375
376 if ( $max <= $count ) {
377 break;
378 }
379 }
380
381 closedir( $handle );
382 }
383 }
384
385
386 add_action(
387 'wpcf7_admin_warnings',
388 'wpcf7_file_display_warning_message',
389 10, 3
390 );
391
392 /**
393 * Displays warning messages about file-uploading fields.
394 */
395 function wpcf7_file_display_warning_message( $page, $action, $object ) {
396 if ( $object instanceof WPCF7_ContactForm ) {
397 $contact_form = $object;
398 } else {
399 return;
400 }
401
402 $has_tags = (bool) $contact_form->scan_form_tags( array(
403 'feature' => 'file-uploading',
404 ) );
405
406 if ( ! $has_tags ) {
407 return;
408 }
409
410 $uploads_dir = wpcf7_upload_tmp_dir();
411
412 if ( ! is_dir( $uploads_dir ) or ! wp_is_writable( $uploads_dir ) ) {
413 $message = sprintf(
414 /* translators: %s: the path of the temporary folder */
415 __( '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' ),
416 $uploads_dir
417 );
418
419 wp_admin_notice( esc_html( $message ), array( 'type' => 'warning' ) );
420 }
421 }
422