<!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" />
<title>[BuddyPress][9760] trunk: Improve `bp_core_get_allowed_avatar_types()`.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { 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 #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#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>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="http://buddypress.trac.wordpress.org/changeset/9760">9760</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://buddypress.trac.wordpress.org/changeset/9760","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>imath</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2015-04-16 23:09:33 +0000 (Thu, 16 Apr 2015)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Improve `bp_core_get_allowed_avatar_types()`. Make sure to get the file type if the upload was not done using html5

The way we used to check the image file type is not working if the browser is Internet Explorer < 10. In this particular case, the Plupload runtime is falling back to flash and the file type is `application/octet-stream`. We are now using `wp_check_filetype_and_ext()` to fix this issue.

You can use the filter `bp_core_get_allowed_avatar_types` if you wish to *restrict* the avatar image types. Our supported types are: jpg, jpeg, png and gif.

Props DJPaul.

Fixes <a href="http://buddypress.trac.wordpress.org/ticket/6336">#6336</a>
See <a href="http://buddypress.trac.wordpress.org/ticket/6290">#6290</a>
See <a href="http://buddypress.trac.wordpress.org/ticket/6278">#6278</a></pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcbpcorebpcoreavatarsphp">trunk/src/bp-core/bp-core-avatars.php</a></li>
<li><a href="#trunktestsphpunittestcasescoreavatarsphp">trunk/tests/phpunit/testcases/core/avatars.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcbpcorebpcoreavatarsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/bp-core/bp-core-avatars.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/bp-core/bp-core-avatars.php     2015-04-16 22:54:11 UTC (rev 9759)
+++ trunk/src/bp-core/bp-core-avatars.php       2015-04-16 23:09:33 UTC (rev 9760)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1321,6 +1321,53 @@
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Get allowed avatar types
+ *
+ * @since  BuddyPress (2.3.0)
+ */
+function bp_core_get_allowed_avatar_types() {
+       $allowed_types = array( 'jpeg', 'gif', 'png' );
+
+       /**
+        * Use this filter to restrict image types
+        *
+        * @since BuddyPress (2.3.0)
+        *
+        * @param array list of image types
+        */
+       $avatar_types = (array) apply_filters( 'bp_core_get_allowed_avatar_types', $allowed_types );
+
+       if ( empty( $avatar_types ) ) {
+               $avatar_types = $allowed_types;
+       } else {
+               $avatar_types = array_intersect( $allowed_types, $avatar_types );
+       }
+
+       return array_values( $avatar_types );
+}
+
+/**
+ * Get allowed avatar mime types
+ *
+ * @since  BuddyPress (2.3.0)
+ */
+function bp_core_get_allowed_avatar_mimes() {
+       $allowed_types  = bp_core_get_allowed_avatar_types();
+       $validate_mimes = wp_match_mime_types( join( ',', $allowed_types ), wp_get_mime_types() );
+       $allowed_mimes  = array_map( 'implode', $validate_mimes );
+
+       /**
+        * Include jpg type if needed so that bp_core_check_avatar_type()
+        * will check for jpeg and jpg extensions.
+        */
+       if ( isset( $allowed_mimes['jpeg'] ) ) {
+               $allowed_mimes['jpg'] = $allowed_mimes['jpeg'];
+       }
+
+       return $allowed_mimes;
+}
+
+/**
</ins><span class="cx" style="display: block; padding: 0 10px">  * Does the current avatar upload have an allowed file type?
</span><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * Permitted file types are JPG, GIF and PNG.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1328,11 +1375,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">  * @param array $file The $_FILES array.
</span><span class="cx" style="display: block; padding: 0 10px">  * @return bool True if the file extension is permitted, otherwise false.
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-function bp_core_check_avatar_type($file) {
-       if ( ( !empty( $file['file']['type'] ) && !preg_match('/(jpe?g|gif|png)$/i', $file['file']['type'] ) ) || !preg_match( '/(jpe?g|gif|png)$/i', $file['file']['name'] ) )
-               return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+function bp_core_check_avatar_type( $file ) {
+       $avatar_filetype = wp_check_filetype_and_ext( $file['file']['tmp_name'], $file['file']['name'], bp_core_get_allowed_avatar_mimes() );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ if ( ! empty( $avatar_filetype['ext'] ) && ! empty( $avatar_filetype['type'] ) ) {
+               return true;
+       }
+
+       return false;
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span></span></pre></div>
<a id="trunktestsphpunittestcasescoreavatarsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/testcases/core/avatars.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/testcases/core/avatars.php    2015-04-16 22:54:11 UTC (rev 9759)
+++ trunk/tests/phpunit/testcases/core/avatars.php      2015-04-16 23:09:33 UTC (rev 9760)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -204,4 +204,106 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $classes = explode( ' ', $matches[1] );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertSame( $expected, array_intersect_key( $expected, $classes ) );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * @group bp_core_check_avatar_type
+        */
+       public function test_bp_core_check_avatar_type() {
+               $plugin_dir = trailingslashit( buddypress()->plugin_dir );
+
+               $file = array(
+                       'file' => array(
+                               'name' => 'humans.txt',
+                               'type' => 'text/plain',
+                               'tmp_name' => $plugin_dir . 'humans.txt',
+                       )
+               );
+
+               $this->assertFalse( bp_core_check_avatar_type( $file ) );
+
+               $file = array(
+                       'file' => array(
+                               'name' => 'mystery-man.jpg',
+                               'type' => 'image/jpeg',
+                               'tmp_name' => $plugin_dir . 'bp-core/images/mystery-man.jpg',
+                       )
+               );
+
+               $this->assertTrue( bp_core_check_avatar_type( $file ) );
+
+               $file = array(
+                       'file' => array(
+                               'name' => 'mystery-man.jpg',
+                               'type' => 'application/octet-stream',
+                               'tmp_name' => $plugin_dir . 'bp-core/images/mystery-man.jpg',
+                       )
+               );
+
+               $this->assertTrue( bp_core_check_avatar_type( $file ), 'flash is using application/octet-stream for image uploads' );
+       }
+
+       /**
+        * @group bp_core_check_avatar_type
+        * @group bp_core_get_allowed_avatar_types
+        */
+       public function test_bp_core_get_allowed_avatar_types_filter() {
+               add_filter( 'bp_core_get_allowed_avatar_types', array( $this, 'avatar_types_filter_add_type' ) );
+
+               $this->assertEquals( array( 'jpeg', 'gif', 'png' ), bp_core_get_allowed_avatar_types() );
+
+               remove_filter( 'bp_core_get_allowed_avatar_types', array( $this, 'avatar_types_filter_add_type' ) );
+
+               add_filter( 'bp_core_get_allowed_avatar_types', array( $this, 'avatar_types_filter_remove_type' ) );
+
+               $this->assertEquals( array( 'gif', 'png' ), bp_core_get_allowed_avatar_types() );
+
+               remove_filter( 'bp_core_get_allowed_avatar_types', array( $this, 'avatar_types_filter_remove_type' ) );
+
+               add_filter( 'bp_core_get_allowed_avatar_types', '__return_empty_array' );
+
+               $this->assertEquals( array( 'jpeg', 'gif', 'png' ), bp_core_get_allowed_avatar_types() );
+
+               remove_filter( 'bp_core_get_allowed_avatar_types', '__return_empty_array' );
+       }
+
+       /**
+        * @group bp_core_check_avatar_type
+        * @group bp_core_get_allowed_avatar_mimes
+        */
+       public function test_bp_core_get_allowed_avatar_mimes() {
+               $mimes = bp_core_get_allowed_avatar_mimes();
+
+               $this->assertEquals( array( 'jpeg', 'gif', 'png', 'jpg' ), array_keys( $mimes ) );
+               $this->assertEquals( array( 'image/jpeg', 'image/gif', 'image/png', 'image/jpeg' ), array_values( $mimes ) );
+
+               add_filter( 'bp_core_get_allowed_avatar_types', array( $this, 'avatar_types_filter_add_type' ) );
+
+               $this->assertEquals( array( 'image/jpeg', 'image/gif', 'image/png', 'image/jpeg' ), array_values( bp_core_get_allowed_avatar_mimes() ) );
+
+               remove_filter( 'bp_core_get_allowed_avatar_types', array( $this, 'avatar_types_filter_add_type' ) );
+
+               add_filter( 'bp_core_get_allowed_avatar_types', array( $this, 'avatar_types_filter_remove_type' ) );
+
+               $this->assertEquals( array( 'image/gif', 'image/png' ), array_values( bp_core_get_allowed_avatar_mimes() ) );
+
+               remove_filter( 'bp_core_get_allowed_avatar_types', array( $this, 'avatar_types_filter_remove_type' ) );
+
+               add_filter( 'bp_core_get_allowed_avatar_types', '__return_empty_array' );
+
+               $this->assertEquals( array( 'image/jpeg', 'image/gif', 'image/png', 'image/jpeg' ), array_values( bp_core_get_allowed_avatar_mimes() ) );
+
+               remove_filter( 'bp_core_get_allowed_avatar_types', '__return_empty_array' );
+       }
+
+       public function avatar_types_filter_add_type( $types ) {
+               $types[] = 'bmp';
+
+               return $types;
+       }
+
+       public function avatar_types_filter_remove_type( $types ) {
+               $jpeg = array_shift( $types );
+
+               return $types;
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre>
</div>
</div>

</body>
</html>