<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" /><style type="text/css"><!--
#msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; }
#msg ul, pre { overflow: auto; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<title>[14649] trunk: Introduce wp_check_filetype_and_ext() to handle mime/
ext image comparisons and corrections for upload and sideload.</title>
</head>
<body>
<div id="msg">
<dl>
<dt>Revision</dt> <dd><a href="http://trac.wordpress.org/changeset/14649">14649</a></dd>
<dt>Author</dt> <dd>nacin</dd>
<dt>Date</dt> <dd>2010-05-15 04:47:03 +0000 (Sat, 15 May 2010)</dd>
</dl>
<h3>Log Message</h3>
<pre>Introduce wp_check_filetype_and_ext() to handle mime/ext image comparisons and corrections for upload and sideload. props Viper007Bond, see <a href="http://trac.wordpress.org/ticket/11946">#11946</a>.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkwpadminincludesfilephp">trunk/wp-admin/includes/file.php</a></li>
<li><a href="#trunkwpincludesfunctionsphp">trunk/wp-includes/functions.php</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkwpadminincludesfilephp"></a>
<div class="modfile"><h4>Modified: trunk/wp-admin/includes/file.php (14648 => 14649)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-admin/includes/file.php        2010-05-14 22:26:07 UTC (rev 14648)
+++ trunk/wp-admin/includes/file.php        2010-05-15 04:47:03 UTC (rev 14649)
</span><span class="lines">@@ -306,10 +306,14 @@
</span><span class="cx">
</span><span class="cx">         // A correct MIME type will pass this test. Override $mimes or use the upload_mimes filter.
</span><span class="cx">         if ( $test_type ) {
</span><del>-                $wp_filetype = wp_check_filetype( $file['name'], $mimes );
</del><ins>+                $wp_filetype = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'], $mimes );
</ins><span class="cx">
</span><span class="cx">                 extract( $wp_filetype );
</span><span class="cx">
</span><ins>+                // Check to see if wp_check_filetype_and_ext() determined the filename was incorrect
+                if ( $proper_filename )
+                        $file['name'] = $proper_filename;
+
</ins><span class="cx">                 if ( ( !$type || !$ext ) && !current_user_can( 'unfiltered_upload' ) )
</span><span class="cx">                         return call_user_func($upload_error_handler, $file, __( 'File type does not meet security guidelines. Try another.' ));
</span><span class="cx">
</span><span class="lines">@@ -416,40 +420,14 @@
</span><span class="cx">
</span><span class="cx">         // A correct MIME type will pass this test. Override $mimes or use the upload_mimes filter.
</span><span class="cx">         if ( $test_type ) {
</span><del>-                $wp_filetype = wp_check_filetype( $file['name'], $mimes );
</del><ins>+                $wp_filetype = wp_check_filetype_and_ext( $file['tmp_name'], $file['name'], $mimes );
</ins><span class="cx">
</span><span class="cx">                 extract( $wp_filetype );
</span><span class="cx">
</span><del>-                // If the file claims to be an image, validate it's extension
-                if ( function_exists('getimagesize') && !empty( $type ) && 'image/' == substr( $type, 0, 6 ) && is_uploaded_file( $file['tmp_name'] ) ) {
-                        // Attempt to figure out what type of image it really is
-                        $imgstats = @getimagesize( $file['tmp_name'] );
</del><ins>+                // Check to see if wp_check_filetype_and_ext() determined the filename was incorrect
+                if ( $proper_filename )
+                        $file['name'] = $proper_filename;
</ins><span class="cx">
</span><del>-                        // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME
-                        if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) {
-                                // This is a simplified array of MIMEs that getimagesize() can detect and their extensions
-                                $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array(
-                                        'image/jpeg' => 'jpg',
-                                        'image/png' => 'png',
-                                        'image/gif' => 'gif',
-                                        'image/bmp' => 'bmp',
-                                        'image/tiff' => 'tif',
-                                ) );
-
-                                // Replace whatever's after the last period in the filename with the correct extension
-                                if ( !empty($mime_to_ext[$imgstats['mime']]) ) {
-                                        $filename_parts = explode( '.', $file['name'] );
-                                        array_pop( $filename_parts );
-                                        $filename_parts[] = $mime_to_ext[$imgstats['mime']];
-                                        $file['name'] = implode( '.', $filename_parts );
-
-                                        // Re-validate the extension / MIME
-                                        $wp_filetype = wp_check_filetype( $file['name'], $mimes );
-                                        extract( $wp_filetype );
-                                }
-                        }
-                }
-
</del><span class="cx">                 if ( ( !$type || !$ext ) && !current_user_can( 'unfiltered_upload' ) )
</span><span class="cx">                         return $upload_error_handler( $file, __( 'File type does not meet security guidelines. Try another.' ));
</span><span class="cx">
</span></span></pre></div>
<a id="trunkwpincludesfunctionsphp"></a>
<div class="modfile"><h4>Modified: trunk/wp-includes/functions.php (14648 => 14649)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/wp-includes/functions.php        2010-05-14 22:26:07 UTC (rev 14648)
+++ trunk/wp-includes/functions.php        2010-05-15 04:47:03 UTC (rev 14649)
</span><span class="lines">@@ -2363,6 +2363,74 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><ins>+ * Attempt to determine the real file type of a file.
+ * If unable to, the file name extension will be used to determine type.
+ *
+ * If it's determined that the extension does not match the file's real type,
+ * then the "proper_filename" value will be set with a proper filename and extension.
+ *
+ * Currently this function only supports validating images known to getimagesize().
+ *
+ * @since 3.0.0
+ *
+ * @param string $file Full path to the image.
+ * @param string $filename The filename of the image (may differ from $file due to $file being in a tmp directory)
+ * @param array $mimes Optional. Key is the file extension with value as the mime type.
+ * @return array Values for the extension, MIME, and either a corrected filename or false if original $filename is valid
+ */
+function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
+
+        $proper_filename = false;
+
+        // Do basic extension validation and MIME mapping
+        $wp_filetype = wp_check_filetype( $filename, $mimes );
+        extract( $wp_filetype );
+
+        // We can't do any further validation without a file to work with
+        if ( ! file_exists( $file ) )
+                return compact( 'ext', 'type', 'proper_filename' );
+
+        // We're able to validate images using GD
+        if ( $type && 0 === strpos( $type, 'image/' ) && function_exists('getimagesize') ) {
+
+                // Attempt to figure out what type of image it actually is
+                $imgstats = @getimagesize( $file );
+
+                // If getimagesize() knows what kind of image it really is and if the real MIME doesn't match the claimed MIME
+                if ( !empty($imgstats['mime']) && $imgstats['mime'] != $type ) {
+                        // This is a simplified array of MIMEs that getimagesize() can detect and their extensions
+                        // You shouldn't need to use this filter, but it's here just in case
+                        $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array(
+                                'image/jpeg' => 'jpg',
+                                'image/png' => 'png',
+                                'image/gif' => 'gif',
+                                'image/bmp' => 'bmp',
+                                'image/tiff' => 'tif',
+                        ) );
+
+                        // Replace whatever is after the last period in the filename with the correct extension
+                        if ( ! empty( $mime_to_ext[ $imgstats['mime'] ] ) ) {
+                                $filename_parts = explode( '.', $filename );
+                                array_pop( $filename_parts );
+                                $filename_parts[] = $mime_to_ext[ $imgstats['mime'] ];
+                                $new_filename = implode( '.', $filename_parts );
+
+                                if ( $new_filename != $filename )
+                                        $proper_filename = $new_filename; // Mark that it changed
+
+                                // Redefine the extension / MIME
+                                $wp_filetype = wp_check_filetype( $new_filename, $mimes );
+                                extract( $wp_filetype );
+                        }
+                }
+        }
+
+        // Let plugins try and validate other types of files
+        // Should return an array in the style of array( 'ext' => $ext, 'type' => $type, 'proper_filename' => $proper_filename )
+        return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
+}
+
+/**
</ins><span class="cx"> * Retrieve list of allowed mime types and file extensions.
</span><span class="cx"> *
</span><span class="cx"> * @since 2.8.6
</span></span></pre>
</div>
</div>
</body>
</html>