PluginProbe ʕ •ᴥ•ʔ
Contact Form 7 / 6.1
Contact Form 7 v6.1
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 11 months ago js 1 year ago swv 11 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 11 months ago filesystem.php 11 months ago form-tag.php 11 months ago form-tags-manager.php 11 months ago formatting.php 11 months ago functions.php 11 months ago html-formatter.php 11 months ago integration.php 11 months ago l10n.php 11 months ago mail-tag.php 11 months ago mail.php 11 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 1 year ago submission.php 11 months ago upgrade.php 11 months ago validation-functions.php 11 months ago validation.php 11 months ago
file.php
433 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 if ( defined( 'WPCF7_UPLOADS_TMP_DIR' ) ) {
330 $dir = path_join( WP_CONTENT_DIR, WPCF7_UPLOADS_TMP_DIR );
331 wp_mkdir_p( $dir );
332
333 if ( wpcf7_is_file_path_in_content_dir( $dir ) ) {
334 return $dir;
335 }
336 }
337
338 $dir = path_join( wpcf7_upload_dir( 'dir' ), 'wpcf7_uploads' );
339 wp_mkdir_p( $dir );
340 return $dir;
341 }
342
343
344 add_action(
345 'shutdown',
346 'wpcf7_cleanup_upload_files',
347 20, 0
348 );
349
350 /**
351 * Cleans up files in the temporary directory for uploaded files.
352 *
353 * @param int $seconds Files older than this are removed. Default 60.
354 * @param int $max Maximum number of files to be removed in a function call.
355 * Default 100.
356 */
357 function wpcf7_cleanup_upload_files( $seconds = 60, $max = 100 ) {
358 $dir = trailingslashit( wpcf7_upload_tmp_dir() );
359
360 if (
361 ! is_dir( $dir ) or
362 ! is_readable( $dir ) or
363 ! wp_is_writable( $dir )
364 ) {
365 return;
366 }
367
368 $seconds = absint( $seconds );
369 $max = absint( $max );
370 $count = 0;
371
372 if ( $handle = opendir( $dir ) ) {
373 while ( false !== ( $file = readdir( $handle ) ) ) {
374 if ( '.' === $file or '..' === $file or '.htaccess' === $file ) {
375 continue;
376 }
377
378 $mtime = @filemtime( path_join( $dir, $file ) );
379
380 if ( $mtime and time() < $mtime + $seconds ) { // less than $seconds old
381 continue;
382 }
383
384 wpcf7_rmdir_p( path_join( $dir, $file ) );
385 $count += 1;
386
387 if ( $max <= $count ) {
388 break;
389 }
390 }
391
392 closedir( $handle );
393 }
394 }
395
396
397 add_action(
398 'wpcf7_admin_warnings',
399 'wpcf7_file_display_warning_message',
400 10, 3
401 );
402
403 /**
404 * Displays warning messages about file-uploading fields.
405 */
406 function wpcf7_file_display_warning_message( $page, $action, $object ) {
407 if ( $object instanceof WPCF7_ContactForm ) {
408 $contact_form = $object;
409 } else {
410 return;
411 }
412
413 $has_tags = (bool) $contact_form->scan_form_tags( array(
414 'feature' => 'file-uploading',
415 ) );
416
417 if ( ! $has_tags ) {
418 return;
419 }
420
421 $uploads_dir = wpcf7_upload_tmp_dir();
422
423 if ( ! is_dir( $uploads_dir ) or ! wp_is_writable( $uploads_dir ) ) {
424 $message = sprintf(
425 /* translators: %s: the path of the temporary folder */
426 __( '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' ),
427 $uploads_dir
428 );
429
430 wp_admin_notice( esc_html( $message ), array( 'type' => 'warning' ) );
431 }
432 }
433