PluginProbe ʕ •ᴥ•ʔ
Contact Form 7 / 5.7.2
Contact Form 7 v5.7.2
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 3 years ago css 3 years ago js 3 years ago swv 3 years ago capabilities.php 7 years ago config-validator.php 3 years ago contact-form-functions.php 3 years ago contact-form-template.php 3 years ago contact-form.php 3 years ago controller.php 3 years ago file.php 3 years ago form-tag.php 3 years ago form-tags-manager.php 3 years ago formatting.php 3 years ago functions.php 3 years ago html-formatter.php 3 years ago integration.php 3 years ago l10n.php 3 years ago mail.php 3 years ago pipe.php 4 years ago pocket-holder.php 3 years ago rest-api.php 4 years ago shortcodes.php 3 years ago special-mail-tags.php 3 years ago submission.php 3 years ago upgrade.php 7 years ago validation-functions.php 3 years ago validation.php 3 years ago
file.php
425 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 $args Optional. Arguments 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, $args = '' ) {
11 $args = wp_parse_args( $args, 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( $args['schema'] ) and isset( $args['name'] ) ) {
37 $result = $args['schema']->validate( array(
38 'file' => true,
39 'field' => $args['name'],
40 ) );
41
42 if ( is_wp_error( $result ) ) {
43 return $result;
44 }
45 }
46
47 // Move uploaded file to tmp dir
48 $uploads_dir = wpcf7_upload_tmp_dir();
49 $uploads_dir = wpcf7_maybe_add_random_dir( $uploads_dir );
50
51 $uploaded_files = array();
52
53 foreach ( $names as $key => $name ) {
54 $tmp_name = $tmp_names[$key];
55
56 if ( empty( $tmp_name ) or ! is_uploaded_file( $tmp_name ) ) {
57 continue;
58 }
59
60 $filename = $name;
61 $filename = wpcf7_canonicalize( $filename, array( 'strto' => 'as-is' ) );
62 $filename = wpcf7_antiscript_file_name( $filename );
63
64 $filename = apply_filters( 'wpcf7_upload_file_name',
65 $filename, $name, $args
66 );
67
68 $filename = wp_unique_filename( $uploads_dir, $filename );
69 $new_file = path_join( $uploads_dir, $filename );
70
71 if ( false === @move_uploaded_file( $tmp_name, $new_file ) ) {
72 return new WP_Error( 'wpcf7_upload_failed',
73 wpcf7_get_message( 'upload_failed' )
74 );
75 }
76
77 // Make sure the uploaded file is only readable for the owner process
78 chmod( $new_file, 0400 );
79
80 $uploaded_files[] = $new_file;
81 }
82
83 return $uploaded_files;
84 }
85
86
87 add_filter(
88 'wpcf7_messages',
89 'wpcf7_file_messages',
90 10, 1
91 );
92
93 /**
94 * A wpcf7_messages filter callback that adds messages for
95 * file-uploading fields.
96 */
97 function wpcf7_file_messages( $messages ) {
98 return array_merge( $messages, array(
99 'upload_failed' => array(
100 'description' => __( "Uploading a file fails for any reason", 'contact-form-7' ),
101 'default' => __( "There was an unknown error uploading the file.", 'contact-form-7' ),
102 ),
103
104 'upload_file_type_invalid' => array(
105 'description' => __( "Uploaded file is not allowed for file type", 'contact-form-7' ),
106 'default' => __( "You are not allowed to upload files of this type.", 'contact-form-7' ),
107 ),
108
109 'upload_file_too_large' => array(
110 'description' => __( "Uploaded file is too large", 'contact-form-7' ),
111 'default' => __( "The uploaded file is too large.", 'contact-form-7' ),
112 ),
113
114 'upload_failed_php_error' => array(
115 'description' => __( "Uploading a file fails for PHP error", 'contact-form-7' ),
116 'default' => __( "There was an error uploading the file.", 'contact-form-7' ),
117 ),
118 ) );
119 }
120
121
122 add_filter(
123 'wpcf7_form_enctype',
124 'wpcf7_file_form_enctype_filter',
125 10, 1
126 );
127
128 /**
129 * A wpcf7_form_enctype filter callback that sets the enctype attribute
130 * to multipart/form-data if the form has file-uploading fields.
131 */
132 function wpcf7_file_form_enctype_filter( $enctype ) {
133 $multipart = (bool) wpcf7_scan_form_tags( array(
134 'feature' => 'file-uploading',
135 ) );
136
137 if ( $multipart ) {
138 $enctype = 'multipart/form-data';
139 }
140
141 return $enctype;
142 }
143
144
145 /**
146 * Converts a MIME type string to an array of corresponding file extensions.
147 *
148 * @param string $mime MIME type.
149 * Wildcard (*) is available for the subtype part.
150 * @return array Corresponding file extensions.
151 */
152 function wpcf7_convert_mime_to_ext( $mime ) {
153 static $mime_types = array();
154
155 $mime_types = wp_get_mime_types();
156
157 $results = array();
158
159 if ( preg_match( '%^([a-z]+)/([*]|[a-z0-9.+-]+)$%i', $mime, $matches ) ) {
160 foreach ( $mime_types as $key => $val ) {
161 if ( '*' === $matches[2] and str_starts_with( $val, $matches[1] . '/' )
162 or $val === $matches[0] ) {
163 $results = array_merge( $results, explode( '|', $key ) );
164 }
165 }
166 }
167
168 $results = array_unique( $results );
169 $results = array_filter( $results );
170 $results = array_values( $results );
171
172 return $results;
173 }
174
175
176 /**
177 * Returns a formatted list of acceptable filetypes.
178 *
179 * @param string|array $types Optional. Array of filetypes.
180 * @param string $format Optional. Pre-defined format designator.
181 * @return string Formatted list of acceptable filetypes.
182 */
183 function wpcf7_acceptable_filetypes( $types = 'default', $format = 'regex' ) {
184 if ( 'default' === $types or empty( $types ) ) {
185 $types = array(
186 'audio/*',
187 'video/*',
188 'image/*',
189 );
190 } else {
191 $types = array_map(
192 function ( $type ) {
193 if ( is_string( $type ) ) {
194 return preg_split( '/[\s|,]+/', strtolower( $type ) );
195 }
196 },
197 (array) $types
198 );
199
200 $types = wpcf7_array_flatten( $types );
201 $types = array_filter( array_unique( $types ) );
202 }
203
204 if ( 'attr' === $format or 'attribute' === $format ) {
205 $types = array_map(
206 function ( $type ) {
207 if ( false === strpos( $type, '/' ) ) {
208 return sprintf( '.%s', trim( $type, '.' ) );
209 } elseif ( preg_match( '%^([a-z]+)/[*]$%i', $type, $matches ) ) {
210 if ( in_array( $matches[1], array( 'audio', 'video', 'image' ) ) ) {
211 return $type;
212 } else {
213 return '';
214 }
215 } elseif ( wpcf7_convert_mime_to_ext( $type ) ) {
216 return $type;
217 }
218 },
219 $types
220 );
221
222 $types = array_filter( $types );
223
224 return implode( ',', $types );
225
226 } elseif ( 'regex' === $format ) {
227 $types = array_map(
228 function ( $type ) {
229 if ( false === strpos( $type, '/' ) ) {
230 return preg_quote( trim( $type, '.' ) );
231 } elseif ( $type = wpcf7_convert_mime_to_ext( $type ) ) {
232 return $type;
233 }
234 },
235 $types
236 );
237
238 $types = wpcf7_array_flatten( $types );
239 $types = array_filter( array_unique( $types ) );
240
241 return implode( '|', $types );
242 }
243
244 return '';
245 }
246
247
248 add_action(
249 'wpcf7_init',
250 'wpcf7_init_uploads',
251 10, 0
252 );
253
254 /**
255 * Initializes the temporary directory for uploaded files.
256 */
257 function wpcf7_init_uploads() {
258 $dir = wpcf7_upload_tmp_dir();
259
260 if ( is_dir( $dir ) and is_writable( $dir ) ) {
261 $htaccess_file = path_join( $dir, '.htaccess' );
262
263 if ( file_exists( $htaccess_file ) ) {
264 list( $first_line_comment ) = (array) file(
265 $htaccess_file,
266 FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES
267 );
268
269 if ( '# Apache 2.4+' === $first_line_comment ) {
270 return;
271 }
272 }
273
274 if ( $handle = @fopen( $htaccess_file, 'w' ) ) {
275 fwrite( $handle, "# Apache 2.4+\n" );
276 fwrite( $handle, "<IfModule authz_core_module>\n" );
277 fwrite( $handle, " Require all denied\n" );
278 fwrite( $handle, "</IfModule>\n" );
279 fwrite( $handle, "\n" );
280 fwrite( $handle, "# Apache 2.2\n" );
281 fwrite( $handle, "<IfModule !authz_core_module>\n" );
282 fwrite( $handle, " Deny from all\n" );
283 fwrite( $handle, "</IfModule>\n" );
284
285 fclose( $handle );
286 }
287 }
288 }
289
290
291 /**
292 * Creates a child directory with a randomly generated name.
293 *
294 * @param string $dir The parent directory path.
295 * @return string The child directory path if created, otherwise the parent.
296 */
297 function wpcf7_maybe_add_random_dir( $dir ) {
298 do {
299 $rand_max = mt_getrandmax();
300 $rand = zeroise( mt_rand( 0, $rand_max ), strlen( $rand_max ) );
301 $dir_new = path_join( $dir, $rand );
302 } while ( file_exists( $dir_new ) );
303
304 if ( wp_mkdir_p( $dir_new ) ) {
305 return $dir_new;
306 }
307
308 return $dir;
309 }
310
311
312 /**
313 * Returns the directory path for uploaded files.
314 *
315 * @return string Directory path.
316 */
317 function wpcf7_upload_tmp_dir() {
318 if ( defined( 'WPCF7_UPLOADS_TMP_DIR' ) ) {
319 $dir = path_join( WP_CONTENT_DIR, WPCF7_UPLOADS_TMP_DIR );
320 wp_mkdir_p( $dir );
321
322 if ( wpcf7_is_file_path_in_content_dir( $dir ) ) {
323 return $dir;
324 }
325 }
326
327 $dir = path_join( wpcf7_upload_dir( 'dir' ), 'wpcf7_uploads' );
328 wp_mkdir_p( $dir );
329 return $dir;
330 }
331
332
333 add_action(
334 'shutdown',
335 'wpcf7_cleanup_upload_files',
336 20, 0
337 );
338
339 /**
340 * Cleans up files in the temporary directory for uploaded files.
341 *
342 * @param int $seconds Files older than this are removed. Default 60.
343 * @param int $max Maximum number of files to be removed in a function call.
344 * Default 100.
345 */
346 function wpcf7_cleanup_upload_files( $seconds = 60, $max = 100 ) {
347 $dir = trailingslashit( wpcf7_upload_tmp_dir() );
348
349 if ( ! is_dir( $dir )
350 or ! is_readable( $dir )
351 or ! wp_is_writable( $dir ) ) {
352 return;
353 }
354
355 $seconds = absint( $seconds );
356 $max = absint( $max );
357 $count = 0;
358
359 if ( $handle = opendir( $dir ) ) {
360 while ( false !== ( $file = readdir( $handle ) ) ) {
361 if ( '.' == $file
362 or '..' == $file
363 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 echo sprintf(
420 '<div class="notice notice-warning"><p>%s</p></div>',
421 esc_html( $message )
422 );
423 }
424 }
425