PluginProbe ʕ •ᴥ•ʔ
Contact Form 7 / 6.1.6
Contact Form 7 v6.1.6
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 11 months ago css 2 weeks ago js 1 year ago swv 9 months ago capabilities.php 7 years ago contact-form-functions.php 11 months ago contact-form-template.php 11 months ago contact-form.php 11 months ago controller.php 11 months ago file.php 9 months ago filesystem.php 11 months ago form-tag.php 7 months ago form-tags-manager.php 11 months ago formatting.php 11 months ago functions.php 9 months ago html-formatter.php 9 months ago integration.php 11 months ago l10n.php 11 months ago mail-tag.php 11 months ago mail.php 3 months ago pipe.php 11 months ago pocket-holder.php 3 years ago rest-api.php 11 months ago shortcodes.php 11 months ago special-mail-tags.php 9 months ago submission.php 9 months ago upgrade.php 11 months ago validation-functions.php 11 months ago validation.php 11 months ago
file.php
441 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 $filesystem = WPCF7_Filesystem::get_instance();
12
13 $options = wp_parse_args( $options, array(
14 'required' => false,
15 'filetypes' => '',
16 'limit' => MB_IN_BYTES,
17 ) );
18
19 foreach ( array( 'name', 'size', 'tmp_name', 'error' ) as $key ) {
20 if ( ! isset( $file[$key] ) ) {
21 $file[$key] = array();
22 }
23 }
24
25 $names = wpcf7_array_flatten( $file['name'] );
26 $sizes = wpcf7_array_flatten( $file['size'] );
27 $tmp_names = wpcf7_array_flatten( $file['tmp_name'] );
28 $errors = wpcf7_array_flatten( $file['error'] );
29
30 foreach ( $errors as $error ) {
31 if ( ! empty( $error ) and UPLOAD_ERR_NO_FILE !== $error ) {
32 return new WP_Error( 'wpcf7_upload_failed_php_error',
33 wpcf7_get_message( 'upload_failed_php_error' )
34 );
35 }
36 }
37
38 if ( isset( $options['schema'] ) and isset( $options['name'] ) ) {
39 $context = array(
40 'file' => true,
41 'field' => $options['name'],
42 );
43
44 foreach ( $options['schema']->validate( $context ) as $result ) {
45 if ( is_wp_error( $result ) ) {
46 return $result;
47 }
48 }
49 }
50
51 // Move uploaded file to tmp dir
52 $uploads_dir = wpcf7_upload_tmp_dir();
53 $uploads_dir = wpcf7_maybe_add_random_dir( $uploads_dir );
54
55 $uploaded_files = array();
56
57 foreach ( $names as $key => $name ) {
58 $tmp_name = $tmp_names[$key];
59
60 if ( empty( $tmp_name ) or ! is_uploaded_file( $tmp_name ) ) {
61 continue;
62 }
63
64 $filename = $name;
65 $filename = wpcf7_canonicalize( $filename, array( 'strto' => 'as-is' ) );
66 $filename = wpcf7_antiscript_file_name( $filename );
67
68 $filename = apply_filters( 'wpcf7_upload_file_name',
69 $filename, $name, $options
70 );
71
72 $filename = wp_unique_filename( $uploads_dir, $filename );
73 $new_file = path_join( $uploads_dir, $filename );
74
75 // phpcs:ignore Generic.PHP.ForbiddenFunctions.Found
76 if ( false === @move_uploaded_file( $tmp_name, $new_file ) ) {
77 return new WP_Error( 'wpcf7_upload_failed',
78 wpcf7_get_message( 'upload_failed' )
79 );
80 }
81
82 // Make sure the uploaded file is only readable for the owner process.
83 $filesystem->chmod( $new_file, 0400 );
84
85 $uploaded_files[] = $new_file;
86 }
87
88 return $uploaded_files;
89 }
90
91
92 add_filter(
93 'wpcf7_messages',
94 'wpcf7_file_messages',
95 10, 1
96 );
97
98 /**
99 * A wpcf7_messages filter callback that adds messages for
100 * file-uploading fields.
101 */
102 function wpcf7_file_messages( $messages ) {
103 return array_merge( $messages, array(
104 'upload_failed' => array(
105 'description' => __( 'Uploading a file fails for any reason', 'contact-form-7' ),
106 'default' => __( 'There was an unknown error uploading the file.', 'contact-form-7' ),
107 ),
108
109 'upload_file_type_invalid' => array(
110 'description' => __( 'Uploaded file is not allowed for file type', 'contact-form-7' ),
111 'default' => __( 'You are not allowed to upload files of this type.', 'contact-form-7' ),
112 ),
113
114 'upload_file_too_large' => array(
115 'description' => __( 'Uploaded file is too large', 'contact-form-7' ),
116 'default' => __( 'The uploaded file is too large.', 'contact-form-7' ),
117 ),
118
119 'upload_failed_php_error' => array(
120 'description' => __( 'Uploading a file fails for PHP error', 'contact-form-7' ),
121 'default' => __( 'There was an error uploading the file.', 'contact-form-7' ),
122 ),
123 ) );
124 }
125
126
127 add_filter(
128 'wpcf7_form_enctype',
129 'wpcf7_file_form_enctype_filter',
130 10, 1
131 );
132
133 /**
134 * A wpcf7_form_enctype filter callback that sets the enctype attribute
135 * to multipart/form-data if the form has file-uploading fields.
136 */
137 function wpcf7_file_form_enctype_filter( $enctype ) {
138 $multipart = (bool) wpcf7_scan_form_tags( array(
139 'feature' => 'file-uploading',
140 ) );
141
142 if ( $multipart ) {
143 $enctype = 'multipart/form-data';
144 }
145
146 return $enctype;
147 }
148
149
150 /**
151 * Converts a MIME type string to an array of corresponding file extensions.
152 *
153 * @param string $mime MIME type.
154 * Wildcard (*) is available for the subtype part.
155 * @return array Corresponding file extensions.
156 */
157 function wpcf7_convert_mime_to_ext( $mime ) {
158 static $mime_types = array();
159
160 $mime_types = wp_get_mime_types();
161
162 $results = array();
163
164 if ( preg_match( '%^([a-z]+)/([*]|[a-z0-9.+-]+)$%i', $mime, $matches ) ) {
165 foreach ( $mime_types as $key => $val ) {
166 if (
167 '*' === $matches[2] and str_starts_with( $val, $matches[1] . '/' ) or
168 $val === $matches[0]
169 ) {
170 $results = array_merge( $results, explode( '|', $key ) );
171 }
172 }
173 }
174
175 $results = array_unique( $results );
176 $results = array_filter( $results );
177 $results = array_values( $results );
178
179 return $results;
180 }
181
182
183 /**
184 * Returns a formatted list of acceptable filetypes.
185 *
186 * @param string|array $types Optional. Array of filetypes.
187 * @param string $format Optional. Pre-defined format designator.
188 * @return string Formatted list of acceptable filetypes.
189 */
190 function wpcf7_acceptable_filetypes( $types = 'default', $format = 'regex' ) {
191 if ( 'default' === $types or empty( $types ) ) {
192 $types = array(
193 'audio/*',
194 'video/*',
195 'image/*',
196 );
197 } else {
198 $types = array_map(
199 static function ( $type ) {
200 if ( is_string( $type ) ) {
201 return preg_split( '/[\s|,]+/', strtolower( $type ) );
202 }
203 },
204 (array) $types
205 );
206
207 $types = wpcf7_array_flatten( $types );
208 $types = array_filter( array_unique( $types ) );
209 }
210
211 if ( 'attr' === $format or 'attribute' === $format ) {
212 $types = array_map(
213 static function ( $type ) {
214 if ( false === strpos( $type, '/' ) ) {
215 return sprintf( '.%s', trim( $type, '.' ) );
216 } elseif ( preg_match( '%^([a-z]+)/[*]$%i', $type, $matches ) ) {
217 if (
218 in_array( $matches[1], array( 'audio', 'video', 'image' ), true )
219 ) {
220 return $type;
221 } else {
222 return '';
223 }
224 } elseif ( wpcf7_convert_mime_to_ext( $type ) ) {
225 return $type;
226 }
227 },
228 $types
229 );
230
231 $types = array_filter( $types );
232
233 return implode( ',', $types );
234
235 } elseif ( 'regex' === $format ) {
236 $types = array_map(
237 static function ( $type ) {
238 if ( false === strpos( $type, '/' ) ) {
239 return preg_quote( trim( $type, '.' ) );
240 } elseif ( $type = wpcf7_convert_mime_to_ext( $type ) ) {
241 return $type;
242 }
243 },
244 $types
245 );
246
247 $types = wpcf7_array_flatten( $types );
248 $types = array_filter( array_unique( $types ) );
249
250 return implode( '|', $types );
251 }
252
253 return '';
254 }
255
256
257 add_action(
258 'wpcf7_init',
259 'wpcf7_init_uploads',
260 10, 0
261 );
262
263 /**
264 * Initializes the temporary directory for uploaded files.
265 */
266 function wpcf7_init_uploads() {
267 $dir = wpcf7_upload_tmp_dir();
268
269 if ( ! is_dir( $dir ) or ! wp_is_writable( $dir ) ) {
270 return;
271 }
272
273 $htaccess_file = path_join( $dir, '.htaccess' );
274
275 if ( file_exists( $htaccess_file ) ) {
276 list( $first_line_comment ) = (array) file(
277 $htaccess_file,
278 FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES
279 );
280
281 if ( '# Apache 2.4+' === $first_line_comment ) {
282 return;
283 }
284 }
285
286 $filesystem = WPCF7_Filesystem::get_instance();
287
288 $htaccess_body = '
289 # Apache 2.4+
290 <IfModule authz_core_module>
291 Require all denied
292 </IfModule>
293
294 # Apache 2.2
295 <IfModule !authz_core_module>
296 Deny from all
297 </IfModule>
298 ';
299
300 $filesystem->put_contents( $htaccess_file, ltrim( $htaccess_body ) );
301 }
302
303
304 /**
305 * Creates a child directory with a randomly generated name.
306 *
307 * @param string $dir The parent directory path.
308 * @return string The child directory path if created, otherwise the parent.
309 */
310 function wpcf7_maybe_add_random_dir( $dir ) {
311 do {
312 $dir_new = path_join( $dir, zeroise( wp_rand(), 10 ) );
313 } while ( file_exists( $dir_new ) );
314
315 if ( wp_mkdir_p( $dir_new ) ) {
316 return $dir_new;
317 }
318
319 return $dir;
320 }
321
322
323 /**
324 * Returns the directory path for uploaded files.
325 *
326 * @return string Directory path.
327 */
328 function wpcf7_upload_tmp_dir() {
329 static $output = '';
330
331 if ( $output ) {
332 return $output;
333 }
334
335 if ( defined( 'WPCF7_UPLOADS_TMP_DIR' ) ) {
336 $dir = path_join( WP_CONTENT_DIR, WPCF7_UPLOADS_TMP_DIR );
337 wp_mkdir_p( $dir );
338
339 if ( wpcf7_is_file_path_in_content_dir( $dir ) ) {
340 return $output = $dir;
341 }
342 }
343
344 $dir = path_join( wpcf7_upload_dir( 'dir' ), 'wpcf7_uploads' );
345 wp_mkdir_p( $dir );
346
347 return $output = $dir;
348 }
349
350
351 add_action(
352 'shutdown',
353 'wpcf7_cleanup_upload_files',
354 20, 0
355 );
356
357 /**
358 * Cleans up files in the temporary directory for uploaded files.
359 *
360 * @param int $seconds Files older than this are removed. Default 60.
361 * @param int $max Maximum number of files to be removed in a function call.
362 * Default 100.
363 */
364 function wpcf7_cleanup_upload_files( $seconds = 60, $max = 100 ) {
365 $dir = trailingslashit( wpcf7_upload_tmp_dir() );
366
367 if (
368 ! is_dir( $dir ) or
369 ! is_readable( $dir ) or
370 ! wp_is_writable( $dir )
371 ) {
372 return;
373 }
374
375 $seconds = absint( $seconds );
376 $max = absint( $max );
377 $count = 0;
378
379 if ( $handle = opendir( $dir ) ) {
380 while ( false !== ( $file = readdir( $handle ) ) ) {
381 if ( '.' === $file or '..' === $file or '.htaccess' === $file ) {
382 continue;
383 }
384
385 $mtime = @filemtime( path_join( $dir, $file ) );
386
387 if ( $mtime and time() < $mtime + $seconds ) { // less than $seconds old
388 continue;
389 }
390
391 wpcf7_rmdir_p( path_join( $dir, $file ) );
392 $count += 1;
393
394 if ( $max <= $count ) {
395 break;
396 }
397 }
398
399 closedir( $handle );
400 }
401 }
402
403
404 add_action(
405 'wpcf7_admin_warnings',
406 'wpcf7_file_display_warning_message',
407 10, 3
408 );
409
410 /**
411 * Displays warning messages about file-uploading fields.
412 */
413 function wpcf7_file_display_warning_message( $page, $action, $object ) {
414 if ( $object instanceof WPCF7_ContactForm ) {
415 $contact_form = $object;
416 } else {
417 return;
418 }
419
420 $has_tags = (bool) $contact_form->scan_form_tags( array(
421 'feature' => 'file-uploading',
422 ) );
423
424 if ( ! $has_tags ) {
425 return;
426 }
427
428 $uploads_dir = wpcf7_upload_tmp_dir();
429
430 if ( ! is_dir( $uploads_dir ) or ! wp_is_writable( $uploads_dir ) ) {
431 wp_admin_notice(
432 sprintf(
433 /* translators: %s: the path of the temporary folder */
434 __( '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' ),
435 $uploads_dir
436 ),
437 array( 'type' => 'warning' )
438 );
439 }
440 }
441