From 25c1592e8a379ec996988ddfbad1abe114378c36 Mon Sep 17 00:00:00 2001 From: Cameron Date: Mon, 7 Dec 2020 15:18:14 -0800 Subject: [PATCH] Issue #4270 WebP support in Media Manager --- e107_handlers/file_class.php | 4 +- e107_handlers/media_class.php | 100 ++++++++++++------ .../tests/_data/fileTest/corrupted_image.webp | 0 e107_tests/tests/unit/e_fileTest.php | 18 +++- e107_tests/tests/unit/e_mediaTest.php | 74 +++++++++---- e107_web/js/plupload/upload.php | 1 - 6 files changed, 138 insertions(+), 59 deletions(-) create mode 100644 e107_tests/tests/_data/fileTest/corrupted_image.webp diff --git a/e107_handlers/file_class.php b/e107_handlers/file_class.php index 2657514be..ab2364d9d 100644 --- a/e107_handlers/file_class.php +++ b/e107_handlers/file_class.php @@ -401,11 +401,11 @@ class e_file * @param boolean $auto_fix_ext * @return array|bool */ - function get_file_info($path_to_file, $imgcheck = true, $auto_fix_ext = true) + public function get_file_info($path_to_file, $imgcheck = true, $auto_fix_ext = true) { $finfo = array(); - if(filesize($path_to_file) < 2) // Don't try and read 0 byte files. + if(!file_exists($path_to_file) || filesize($path_to_file) < 2) // Don't try and read 0 byte files. { return false; } diff --git a/e107_handlers/media_class.php b/e107_handlers/media_class.php index 61ee6c217..0b8e923fa 100644 --- a/e107_handlers/media_class.php +++ b/e107_handlers/media_class.php @@ -38,7 +38,7 @@ class e_media 'multipart' => array(), 'application' => array('zip','doc','gz'), 'audio' => array('mp3','wav'), - 'image' => array('jpeg','jpg','png','gif', 'svg'), + 'image' => array('jpeg','jpg','png','gif', 'svg', 'webp'), 'video' => array('mp4', 'youtube','youtubepl'), 'other' => array(), // 'glyph' => array('glyph') @@ -568,6 +568,7 @@ class e_media $id = $row['media_id']; $ret[$id] = $row; } + return $ret; } @@ -1128,7 +1129,7 @@ class e_media list($pmime,$tmp) = explode('/',$mime); unset($tmp); - if(!vartrue($this->mimePaths[$pmime])) + if(empty($this->mimePaths[$pmime])) { $this->log("Couldn't detect mime-type ($mime)."); $text = $text = str_replace('[x]',$mime,IMALAN_111); //FIXME LAN IMALAN_112 is not generic. This method can be called from anywhere, not only e107_admin/image.php. @@ -1263,7 +1264,7 @@ class e_media $info = e107::getFile()->get_file_info($path); - + $this->log("File info for $path : ".print_r($info,true)); @@ -1443,10 +1444,11 @@ class e_media return $path; } - $ext = e107::getFile()->getFileExtension($mime); - if($ext && (substr($path,-4) != $ext)) + $len = strlen($ext); + + if($ext && (substr($path,- $len) != $ext)) { return $path.$ext; } @@ -1999,7 +2001,6 @@ class e_media if(!file_exists($jpgFile)) { - switch($type) { case ".gif": @@ -2061,13 +2062,13 @@ class e_media $fileName = $_FILES['file']['name']; } + // Clean the fileName for security reasons $fileName = preg_replace('/[^\w\._]+/', '_', $fileName); // $array = array("jsonrpc" => "2.0", "error" => array('code'=>$_FILES['file']['error'], 'message'=>'Failed to move file'), "id" => "id", 'data'=>$_FILES ); - // Make sure the fileName is unique but only if chunking is disabled if($chunks < 2 && file_exists($targetDir . $fileName)) { @@ -2084,6 +2085,7 @@ class e_media $fileName = $fileName_a . '_' . $count . $fileName_b; } + $filePath = $targetDir . $fileName; // Create target dir @@ -2139,7 +2141,7 @@ class e_media if($out) { // Read binary input stream and append it to temp file - $tmpName = e107::getParser()->filter($_FILES['file']['tmp_name'],'str'); + $tmpName = e107::getParser()->filter($_FILES['file']['tmp_name']); $in = fopen($tmpName, "rb"); if($in) @@ -2224,9 +2226,32 @@ class e_media rename("{$filePath}.part", $filePath); } + return $this->processAjaxImport($filePath, $_REQUEST); + + } + + /** + * For Internal Use Only + * Second half of processAjaxUpload() + * Subject to change at any time. Use at own risk. + * + * @param string $filePath + * @param array $request + * @return false|string + */ + public function processAjaxImport($filePath, $request = array()) + { + if(!file_exists($filePath)) + { + return '{"jsonrpc" : "2.0", "error" : {"code": 110, "message": "File Not Found: '.$filePath.'"}, "id" : "id"}'; + } + + $targetDir = e_IMPORT; + $fileName = basename($filePath); + if(e107::getFile()->isClean($filePath) !== true) { - $this->ajaxUploadLog($filePath,$fileName, filesize($filePath), false); + $this->ajaxUploadLog($filePath, $fileName, filesize($filePath), false, "File detected as not clean. (".__METHOD__.")"); @unlink($filePath); return '{"jsonrpc" : "2.0", "error" : {"code": 104, "message": "Bad File Detected. '.$filePath.'"}, "id" : "id"}'; } @@ -2234,14 +2259,14 @@ class e_media $convertToJpeg = e107::getPref('convert_to_jpeg', 0); - if(!empty($_REQUEST['convert']) && $_REQUEST['convert'] === 'jpg') + if(!empty($request['convert']) && $request['convert'] === 'jpg') { $convertToJpeg = true; } $fileSize = filesize($filePath); - if(varset($_REQUEST['for']) !== '_icon' && !empty($convertToJpeg)) + if(varset($request['for']) !== '_icon' && !empty($convertToJpeg)) { if($jpegFile = e107::getMedia()->convertImageToJpeg($filePath, true)) { @@ -2252,12 +2277,12 @@ class e_media } - if(!empty($_REQUEST['resize'])) + if(!empty($request['resize'])) { $thumb = Intervension::make($filePath); - $w = (int) $_REQUEST['resize']['w']; - $h = (int) $_REQUEST['resize']['h']; + $w = (int) $request['resize']['w']; + $h = (int) $request['resize']['h']; $thumb->resize(vartrue($w, null), vartrue($h, null), function ($constraint) { @@ -2269,9 +2294,9 @@ class e_media } - if(!empty($_REQUEST['rename'])) + if(!empty($request['rename'])) { - $newPath = $targetDir.basename($_REQUEST['rename']); + $newPath = $targetDir.basename($request['rename']); if(!rename($filePath, $newPath)) { return '{"jsonrpc" : "2.0", "error" : {"code": 105, "message": "Unable to rename '.$filePath.' to '.$newPath.'"}, "id" : "id"}'; @@ -2279,13 +2304,18 @@ class e_media $fileName = basename($newPath); } - if(!empty($_REQUEST['for'])) // leave in upload directory if no category given. + $msg = ''; + + if(!empty($request['for'])) // leave in upload directory if no category given. { - $uploadPath = varset($_REQUEST['path'],null); - $for = e107::getParser()->filter($_REQUEST['for']); + $uploadPath = varset($request['path'],null); + $for = e107::getParser()->filter($request['for']); $for = str_replace(array('+','^'),'', $for); - $result = e107::getMedia()->importFile($fileName, $for, array('path'=>$uploadPath)); + if(!$result = e107::getMedia()->importFile($fileName, $for, array('path'=>$uploadPath))) + { + $msg = 'Unable to import ('.__METHOD__.' Line: '.__LINE__ .')'; + } } else { @@ -2293,43 +2323,45 @@ class e_media } - $this->ajaxUploadLog($filePath,$fileName,$fileSize,$result); - - - - // file_put_contents(e_LOG."mediatmp.log", print_r($previewArr,true)); + $this->ajaxUploadLog($filePath,$fileName,$fileSize,$result, $msg); $opts = array(); // set correct size for preview image. - if(isset($_REQUEST['w'])) + if(isset($request['w'])) { - $opts['w'] = (int) $_REQUEST['w']; + $opts['w'] = (int) $request['w']; } - if(isset($_REQUEST['h'])) + if(isset($request['h'])) { - $opts['h'] = (int) $_REQUEST['h']; + $opts['h'] = (int) $request['h']; } $preview = $this->previewTag($result,$opts); $array = array("jsonrpc" => "2.0", "result" => $result, "id" => "id", 'preview' => $preview, 'data'=>$_FILES ); return json_encode($array); - - + + } - - private function ajaxUploadLog($filePath,$fileName,$fileSize,$result) + private function ajaxUploadLog($filePath,$fileName,$fileSize,$result, $msg='') { - $log = e107::getParser()->filter($_GET,'str'); + $log = e107::getParser()->filter($_GET); + $log['filepath'] = str_replace('../','',$filePath); $log['filename'] = $fileName; $log['filesize'] = $fileSize; $log['status'] = ($result) ? 'ok' : 'failed'; $log['_files'] = $_FILES; $log['_request'] = $_REQUEST; + + if(!empty($msg)) + { + $log['_msg'] = $msg; + } + // $log['_get'] = $_GET; // $log['_post'] = $_POST; $type = ($result) ? E_LOG_INFORMATIVE : E_LOG_WARNING; diff --git a/e107_tests/tests/_data/fileTest/corrupted_image.webp b/e107_tests/tests/_data/fileTest/corrupted_image.webp new file mode 100644 index 000000000..e69de29bb diff --git a/e107_tests/tests/unit/e_fileTest.php b/e107_tests/tests/unit/e_fileTest.php index 175939982..8e852c050 100644 --- a/e107_tests/tests/unit/e_fileTest.php +++ b/e107_tests/tests/unit/e_fileTest.php @@ -237,12 +237,24 @@ class e_fileTest extends \Codeception\Test\Unit public function testGet_file_info() { - $path = APP_PATH."/e107_web/lib/font-awesome/4.7.0/fonts/fontawesome-webfont.svg"; + $tests = array( + 0 => array('input' => "e107_web/lib/font-awesome/4.7.0/fonts/fontawesome-webfont.svg", 'expected'=>'image/svg+xml'), + 1 => array('input' => "e107_plugins/gallery/images/beach.webp", 'expected'=>'image/webp'), + 2 => array('input' => "e107_tests/tests/_data/fileTest/corrupted_image.webp", 'expected'=>false), + ); - $ret = $this->fl->get_file_info($path); + foreach($tests as $item) + { + $path = APP_PATH.'/'.$item['input']; + $ret = $this->fl->get_file_info($path); - $this->assertEquals('image/svg+xml',$ret['mime']); + if($ret === false) + { + $ret = array('mime'=>false); + } + $this->assertEquals($item['expected'], $ret['mime']); + } } /* diff --git a/e107_tests/tests/unit/e_mediaTest.php b/e107_tests/tests/unit/e_mediaTest.php index a61e874b8..9b8396e1e 100644 --- a/e107_tests/tests/unit/e_mediaTest.php +++ b/e107_tests/tests/unit/e_mediaTest.php @@ -23,7 +23,7 @@ } catch (Exception $e) { - $this->fail("Couldn't load e_media object"); + $this->fail($e->getMessage()); } } @@ -37,25 +37,58 @@ array('path'=>'path-to-file/audio' , 'mime' => 'audio/mpeg', 'expected'=>'path-to-file/audio.mp3'), array('path'=>'path-to-file/audio.mp3', 'mime' => 'audio/mpeg', 'expected'=>'path-to-file/audio.mp3'), array('path'=>'path-to-file/image.svg', 'mime' => 'svg+xml', 'expected'=>'path-to-file/image.svg'), + array('path'=>'path-to-file/image.webp', 'mime' => 'svg+xml', 'expected'=>'path-to-file/image.webp'), ); foreach($types as $val) { $actual = $this->md->checkFileExtension($val['path'],$val['mime']); - $this->assertEquals($val['expected'],$actual); - //echo ($actual)."\n"; } - - } - public function testProcessAjaxUpload() + public function testProcessAjaxImport() { + $tests = array( + 0 => array( + 'file' => e_PLUGIN."gallery/images/horse.jpg", + 'param' => array ( + 'for' => 'news ', + 'w' => '206', + 'h' => '190', + ), + ), + 1 => array( + 'file' => e_PLUGIN."gallery/images/beach.webp", + 'param' => array ( + 'for' => 'news ', + 'w' => '206', + 'h' => '190', + ), + ), - // @todo + ); + + foreach($tests as $index => $var) + { + $source = $var['file']; + $file = e_IMPORT.basename($var['file']); + copy($source,$file); + + $json = $this->md->processAjaxImport($file,$var['param']); + + $result = json_decode($json, JSON_PRETTY_PRINT); + // var_dump($result); + $this->assertNotFalse($result); + + // var_dump($result); + + $this->assertStringEndsWith('/'.basename($var['file']), $result['result']); + + $this->assertNotEmpty($result['preview']); + } } @@ -99,26 +132,29 @@ */ public function testImportFile() { - /* FIXME: https://github.com/e107inc/e107/issues/4033 - $icon = codecept_data_dir()."icon_64.png"; - $dest = e_IMPORT."icon_64.png"; - copy($icon,$dest); + /* FIXME: https://github.com/e107inc/e107/issues/4033 */ - if(!file_exists($dest)) - { - $this->fail("Couldn't copy icon to ".$dest); - } $tests = array( - 0 => array('file'=> 'icon_64.png', 'cat' => '_icon', 'expected'=>"{e_MEDIA_ICON}icon_64.png"), + // 0 => array('file'=> codecept_data_dir().'icon_64.png', 'cat' => '_icon', 'expected'=>"{e_MEDIA_ICON}icon_64.png"), + 1 => array('file'=> e_PLUGIN.'gallery/images/horse.jpg', 'cat' => 'news', 'expected'=>"horse.jpg"), + 2 => array('file'=> e_PLUGIN.'gallery/images/beach.webp', 'cat' => 'news', 'expected'=>"beach.webp"), ); foreach($tests as $var) { - $result = $this->md->importFile($var['file'], $var['cat']); - $this->assertEquals($var['expected'],$result); + $importPath = e_IMPORT.basename($var['file']); + copy($var['file'], $importPath); + + if(!file_exists($importPath)) + { + $this->fail("Couldn't copy file to ".$importPath); + } + + $result = $this->md->importFile($importPath, $var['cat']); + $this->assertStringEndsWith($var['expected'],$result); } - */ + } /* public function testBrowserCarousel() diff --git a/e107_web/js/plupload/upload.php b/e107_web/js/plupload/upload.php index 2ea894ff1..6ccd8be26 100644 --- a/e107_web/js/plupload/upload.php +++ b/e107_web/js/plupload/upload.php @@ -33,4 +33,3 @@ exit; -?> \ No newline at end of file