diff --git a/common/framework/filters/filecontentfilter.php b/common/framework/filters/filecontentfilter.php index 620202245..822bfa546 100644 --- a/common/framework/filters/filecontentfilter.php +++ b/common/framework/filters/filecontentfilter.php @@ -7,6 +7,11 @@ namespace Rhymix\Framework\Filters; */ class FileContentFilter { + /** + * Fileinfo instance cache + */ + protected static $_finfo = null; + /** * Generic checker * @@ -28,8 +33,9 @@ class FileContentFilter return false; } - // Get the extension. + // Get the extension and MIME type. $ext = $filename ? strtolower(substr(strrchr($filename, '.'), 1)) : ''; + $mime_type = self::_getMimetype($file, true); // Check the first 4KB of the file for possible XML content. $fp = fopen($file, 'rb'); @@ -43,6 +49,20 @@ class FileContentFilter return false; } + // Check other image files. + if (in_array($ext, array('jpg', 'jpeg', 'png', 'gif')) && $mime_type !== false && $mime_type !== 'image') + { + fclose($fp); + return false; + } + + // Check audio and video files. + if (preg_match('/(wm[va]|mpe?g|avi|flv|mp[1-4]|as[fx]|wav|midi?|moo?v|qt|r[am]{1,2}|m4v)$/', $file) && $mime_type !== false && $mime_type !== 'audio' && $mime_type !== 'video') + { + fclose($fp); + return false; + } + // Check XML files. if (($ext === 'xml' || $is_xml) && !self::_checkXML($fp, 0, $filesize)) { @@ -149,4 +169,29 @@ class FileContentFilter } return false; } + + /** + * Attempt to detect the MIME type of a file. + * + * @param string $file Path of file to check + * @param bool $trim_subtype Whether to remove the subtype from the return value + * @return string|false + */ + protected static function _getMimetype($file, $trim_subtype = false) + { + if (!class_exists('finfo')) + { + return false; + } + if (!self::$_finfo) + { + self::$_finfo = new \finfo(FILEINFO_MIME_TYPE); + } + $mime_type = self::$_finfo->file($file); + if ($trim_subtype) + { + $mime_type = strstr($mime_type, '/', true); + } + return $mime_type; + } } diff --git a/common/legacy.php b/common/legacy.php index 0f7644065..78f3f7d83 100644 --- a/common/legacy.php +++ b/common/legacy.php @@ -868,7 +868,7 @@ function removeSrcHack($match) * @param string $file Taget file path * @return bool */ -function checkUploadedFile($file) +function checkUploadedFile($file, $filename = null) { return true; } diff --git a/modules/comment/comment.controller.php b/modules/comment/comment.controller.php index 6853a5f63..2dc2fb651 100644 --- a/modules/comment/comment.controller.php +++ b/modules/comment/comment.controller.php @@ -440,7 +440,7 @@ class commentController extends comment if($obj->homepage) { - $obj->homepage = removeHackTag($obj->homepage); + $obj->homepage = escape($obj->homepage); if(!preg_match('/^[a-z]+:\/\//i',$obj->homepage)) { $obj->homepage = 'http://'.$obj->homepage; @@ -803,7 +803,7 @@ class commentController extends comment if($obj->homepage) { - $obj->homepage = removeHackTag($obj->homepage); + $obj->homepage = escape($obj->homepage); if(!preg_match('/^[a-z]+:\/\//i',$obj->homepage)) { $obj->homepage = 'http://'.$obj->homepage; diff --git a/modules/comment/comment.item.php b/modules/comment/comment.item.php index 1b704803c..927a1a767 100644 --- a/modules/comment/comment.item.php +++ b/modules/comment/comment.item.php @@ -287,12 +287,12 @@ class commentItem extends BaseObject return; } - if(strncasecmp('http://', $url, 7) !== 0) + if(!preg_match('@^[a-z]+://@i', $url)) { - $url = "http://" . $url; + $url = 'http://' . $url; } - return htmlspecialchars($url, ENT_COMPAT | ENT_HTML401, 'UTF-8', false); + return escape($url, false); } function getMemberSrl() @@ -302,17 +302,17 @@ class commentItem extends BaseObject function getUserID() { - return htmlspecialchars($this->get('user_id'), ENT_COMPAT | ENT_HTML401, 'UTF-8', false); + return escape($this->get('user_id'), false); } function getUserName() { - return htmlspecialchars($this->get('user_name'), ENT_COMPAT | ENT_HTML401, 'UTF-8', false); + return escape($this->get('user_name'), false); } function getNickName() { - return htmlspecialchars($this->get('nick_name'), ENT_COMPAT | ENT_HTML401, 'UTF-8', false); + return escape($this->get('nick_name'), false); } function getVote() diff --git a/modules/document/document.controller.php b/modules/document/document.controller.php index 0cb5d54b0..9e4f8d3e5 100644 --- a/modules/document/document.controller.php +++ b/modules/document/document.controller.php @@ -387,7 +387,7 @@ class documentController extends document if($obj->allow_trackback!='Y') $obj->allow_trackback = 'N'; if($obj->homepage) { - $obj->homepage = removeHackTag($obj->homepage); + $obj->homepage = escape($obj->homepage); if(!preg_match('/^[a-z]+:\/\//i',$obj->homepage)) { $obj->homepage = 'http://'.$obj->homepage; @@ -517,7 +517,10 @@ class documentController extends document } // Remove iframe and script if not a top adminisrator in the session. - if($logged_info->is_admin != 'Y') $obj->content = removeHackTag($obj->content); + if($logged_info->is_admin != 'Y') + { + $obj->content = removeHackTag($obj->content); + } // An error appears if both log-in info and user name don't exist. if(!$logged_info->member_srl && !$obj->nick_name) return new BaseObject(-1, 'msg_invalid_request'); @@ -692,7 +695,7 @@ class documentController extends document if($obj->allow_trackback!='Y') $obj->allow_trackback = 'N'; if($obj->homepage) { - $obj->homepage = removeHackTag($obj->homepage); + $obj->homepage = escape($obj->homepage); if(!preg_match('/^[a-z]+:\/\//i',$obj->homepage)) { $obj->homepage = 'http://'.$obj->homepage; diff --git a/modules/document/document.item.php b/modules/document/document.item.php index 853fb8afa..302d84a6f 100644 --- a/modules/document/document.item.php +++ b/modules/document/document.item.php @@ -438,7 +438,7 @@ class documentItem extends BaseObject $url = 'http://' . $url; } - return $url; + return escape($url, false); } function getMemberSrl() diff --git a/modules/file/file.controller.php b/modules/file/file.controller.php index 0cfec0145..d9887391e 100644 --- a/modules/file/file.controller.php +++ b/modules/file/file.controller.php @@ -136,18 +136,25 @@ class fileController extends file // Save the file $output = $this->insertFile($file_info, $module_srl, $upload_target_srl); + if($output->error != '0') + { + throw new Rhymix\Framework\Exception($output->message); + } + // Create the response Context::setResponseMethod('JSON'); $this->add('file_srl', $output->get('file_srl')); $this->add('file_size', $output->get('file_size')); $this->add('direct_download', $output->get('direct_download')); $this->add('source_filename', $output->get('source_filename')); $this->add('upload_target_srl', $output->get('upload_target_srl')); - $this->add('download_url', $oFileModel->getDirectFileUrl($output->get('uploaded_filename'))); - - if($output->error != '0') + if ($output->get('direct_download') === 'Y') { - throw new Rhymix\Framework\Exception($output->message); + $this->add('download_url', $oFileModel->getDirectFileUrl($output->get('uploaded_filename'))); + } + else + { + $this->add('download_url', $oFileModel->getDownloadUrl($output->get('file_srl'), $output->get('sid'), $module_srl)); } } @@ -1291,13 +1298,14 @@ class fileController extends file // 2: 년월일 단위로 정리 if ($folder_structure == 2) { - return sprintf('%sfiles/attach/%s/%04d/%02d/%02d/', $prefix, $file_type, substr($regdate, 0, 4), substr($regdate, 4, 2), substr($regdate, 6, 2)); + return sprintf('%sfiles/attach/%s/%04d/%02d/%02d/', $prefix, $file_type, substr($regdate, 0, 4), substr($regdate, 4, 2), substr($regdate, 6, 2)); } // 1 or 0: module_srl 및 업로드 대상 번호에 따라 3자리씩 끊어서 정리 else { - return sprintf('%sfiles/attach/%s/%d/%s', $prefix, $file_type, $module_srl, getNumberingPath($upload_target_srl, 3)); + $components = $upload_target_srl ? getNumberingPath($upload_target_srl, 3) : ''; + return sprintf('%sfiles/attach/%s/%d/%s', $prefix, $file_type, $module_srl, $components); } } diff --git a/modules/module/module.controller.php b/modules/module/module.controller.php index 3191fdf98..0f08bddca 100644 --- a/modules/module/module.controller.php +++ b/modules/module/module.controller.php @@ -1163,7 +1163,9 @@ class moduleController extends module $path = $oModuleModel->getModuleFileBoxPath($vars->module_filebox_srl); FileHandler::makeDir($path); - $save_filename = sprintf('%s%s.%s',$path, $vars->module_filebox_srl, $ext); + $random = Rhymix\Framework\Security::getRandom(32, 'hex'); + $ext = substr(strrchr($vars->addfile['name'], '.'), 1); + $save_filename = sprintf('%s%s.%s', $path, $random, $ext); $tmp = $vars->addfile['tmp_name']; if(!@move_uploaded_file($tmp, $save_filename)) @@ -1171,7 +1173,7 @@ class moduleController extends module return false; } - $args->fileextension = strtolower(substr(strrchr($vars->addfile['name'],'.'),1)); + $args->fileextension = $ext; $args->filename = $save_filename; $args->filesize = $vars->addfile['size']; } @@ -1197,7 +1199,10 @@ class moduleController extends module $oModuleModel = getModel('module'); $path = $oModuleModel->getModuleFileBoxPath($vars->module_filebox_srl); FileHandler::makeDir($path); - $save_filename = sprintf('%s%s.%s',$path, $vars->module_filebox_srl, $vars->ext); + + $random = Rhymix\Framework\Security::getRandom(32, 'hex'); + $ext = substr(strrchr($vars->addfile['name'], '.'), 1); + $save_filename = sprintf('%s%s.%s', $path, $random, $ext); $tmp = $vars->addfile['tmp_name']; // upload @@ -1212,7 +1217,7 @@ class moduleController extends module $args->member_srl = $vars->member_srl; $args->comment = $vars->comment; $args->filename = $save_filename; - $args->fileextension = strtolower(substr(strrchr($vars->addfile['name'],'.'),1)); + $args->fileextension = $ext; $args->filesize = $vars->addfile['size']; $output = executeQuery('module.insertModuleFileBox', $args); diff --git a/modules/module/module.model.php b/modules/module/module.model.php index c40cd1f6a..335a8bebe 100644 --- a/modules/module/module.model.php +++ b/modules/module/module.model.php @@ -2393,7 +2393,7 @@ class moduleModel extends module function getModuleFileBoxPath($module_filebox_srl) { - return sprintf("./files/attach/filebox/%s",getNumberingPath($module_filebox_srl,3)); + return getController('file')->getStoragePath('filebox', 0, $module_filebox_srl); } /**