* Date: 2018-4-3 */ namespace app\admin\logic; use think\Model; use think\Db; /** * 文件管理逻辑定义 * Class CatsLogic * @package admin\Logic */ class FilemanagerLogic extends Model { public $globalTpCache = array(); public $baseDir = ''; // 服务器站点根目录绝对路径 public $maxDir = ''; public $replaceImgOpArr = array(); // 替换权限 public $editOpArr = array(); // 编辑权限 public $renameOpArr = array(); // 改名权限 public $delOpArr = array(); // 删除权限 public $moveOpArr = array(); // 移动权限 public $editExt = array(); // 允许新增/编辑扩展名文件 public $disableFuns = array(); // 允许新增/编辑扩展名文件 /** * 析构函数 */ function __construct() { $this->globalTpCache = tpCache('global'); $this->baseDir = rtrim(ROOT_PATH, DS); // 服务器站点根目录绝对路径 $this->maxDir = $this->globalTpCache['web_templets_dir']; // 默认文件管理的最大级别目录 // 替换权限 $this->replaceImgOpArr = array('gif','jpg','svg'); // 编辑权限 $this->editOpArr = array('txt','htm','js','css'); // 改名权限 $this->renameOpArr = array('dir','gif','jpg','svg','flash','zip','exe','mp3','wmv','rm','txt','htm','js','css','other'); // 删除权限 $this->delOpArr = array('dir','gif','jpg','svg','flash','zip','exe','mp3','wmv','rm','txt','htm','php','js','css','other'); // 移动权限 $this->moveOpArr = array('gif','jpg','svg','flash','zip','exe','mp3','wmv','rm','txt','htm','js','css','other'); // 允许新增/编辑扩展名文件 $this->editExt = array('htm','js','css','txt'); // 过滤php危险函数 $this->disableFuns = ['phpinfo']; } /** * 编辑文件 * * @access public * @param string $filename 文件名 * @param string $activepath 当前路径 * @param string $content 文件内容 * @return string */ public function editFile($filename, $activepath = '', $content = '') { $security = tpSetting('security'); if (empty($security['security_ask_open']) || empty($security['security_answer'])) { return '需要开启二次验证密码'; } else { $admin_id = session('?admin_id') ? (int)session('admin_id') : 0; $admin_info = Db::name('admin')->field('admin_id,last_ip')->where(['admin_id'=>$admin_id])->find(); // 当前管理员二次安全验证过的IP地址 $security_answerverify_ip = !empty($security['security_answerverify_ip']) ? $security['security_answerverify_ip'] : '-1'; // 同IP不验证 if (empty($admin_info) || $admin_info['last_ip'] != $security_answerverify_ip) { return '出于安全考虑,请勿非法越过二次安全验证'; } } $fileinfo = pathinfo($filename); $ext = strtolower($fileinfo['extension']); $filename = trim($fileinfo['filename'], '.').'.'.$fileinfo['extension']; /*不允许越过指定最大级目录的文件编辑*/ $tmp_max_dir = preg_replace("#\/#i", "\/", $this->maxDir); if (!preg_match("#^".$tmp_max_dir."#i", $activepath)) { return '没有操作权限!'; } /*--end*/ /*允许编辑的文件类型*/ if (!in_array($ext, $this->editExt)) { return '只允许操作文件类型如下:'.implode('|', $this->editExt); } /*--end*/ $file = $this->baseDir."$activepath/$filename"; if (!is_writable(dirname($file))) { return "请把模板文件目录设置为可写入权限!"; } if ('htm' == $ext) { $content = htmlspecialchars_decode($content, ENT_QUOTES); if (preg_match('#<([^?]*)\?php#i', $content) || preg_match('#<\?(\s*)=#i', $content) || (preg_match('#<\?#i', $content) && preg_match('#\?>#i', $content)) || preg_match('#\{eyou\:php([^\}]*)\}#i', $content) || preg_match('#\{php([^\}]*)\}#i', $content) || preg_match('#(\s+)language(\s*)=(\s*)("|\')?php("|\')?#i', $content)) { return "模板里不允许有php语法,为了安全考虑,请通过FTP工具进行编辑上传。"; } foreach ($this->disableFuns as $key => $val) { $val_new = msubstr($val, 0, 1).'-'.msubstr($val, 1); $content = preg_replace("/(@)?".$val."(\s*)\(/i", "{$val_new}(", $content); } } $fp = fopen($file, "w"); fputs($fp, $content); fclose($fp); return true; } /** * 上传文件 * * @param string $dirname 新目录 * @param string $activepath 当前路径 * @param boolean $replace 是否替换 * @param string $type 文件类型:图片image , 附件file , 视频media */ public function upload($fileElementId, $activepath = '', $replace = false, $type = 'image') { $retData = []; $file = request()->file($fileElementId); if (is_object($file) && !is_array($file)) { $retData = $this->uploadfile($file, $activepath, $replace, $type); } else if (!is_object($file) && is_array($file)) { $fileArr = $file; $i = 0; $j = 0; foreach ($fileArr as $key => $fileObj) { if (empty($fileObj)) { continue; } $res = $this->uploadfile($fileObj, $activepath, $replace, $type); if(!empty($res['code']) && $res['code'] == 1) { $i++; } else { $j++; } } if ($j == 0) { $retData['code'] = 0; $retData['msg'] = "上传失败 $i 个文件到: $activepath"; } else { $retData['code'] = 1; $retData['msg'] = "上传成功!"; } } return $retData; } /** * 自定义上传 * * @param object $file 文件对象 * @param string $activepath 当前路径 * @param boolean $replace 是否替换 * @param string $type 文件类型:图片image , 附件file , 视频media */ public function uploadfile($file, $activepath = '', $replace = false, $type = 'image') { $validate = array(); /*文件类型限制*/ switch ($type) { case 'image': $validate_ext = tpCache('basic.image_type'); break; case 'file': $validate_ext = tpCache('basic.file_type'); break; case 'media': $validate_ext = tpCache('basic.media_type'); break; default: $validate_ext = tpCache('basic.image_type'); break; } $validate['ext'] = explode('|', $validate_ext); /*--end*/ /*文件大小限制*/ $validate_size = tpCache('basic.file_size'); if (!empty($validate_size)) { $validate['size'] = $validate_size * 1024 * 1024; // 单位为b } /*--end*/ /*上传文件验证*/ if (!empty($validate)) { $is_validate = $file->check($validate); if ($is_validate === false) { return ['code'=>0, 'msg'=>$file->getError()]; } } /*--end*/ $savePath = !empty($activepath) ? trim($activepath, '/') : UPLOAD_PATH.'temp'; if (!file_exists($savePath)) { tp_mkdir($savePath); } if (false == $replace) { $fileinfo = $file->getInfo(); $filename = pathinfo($fileinfo['name'], PATHINFO_BASENAME); //获取上传文件名 } else { $filename = $replace; } $fileExt = pathinfo($filename, PATHINFO_EXTENSION); //获取上传文件扩展名 if (!in_array($fileExt, $validate['ext'])) { return ['code'=>0, 'msg'=>'上传文件后缀不允许']; } // 使用自定义的文件保存规则 $info = $file->move($savePath, $filename, true); if($info){ return ['code'=>1, 'msg'=>'上传成功']; }else{ return ['code'=>0, 'msg'=>$file->getError()]; } } /** * 当前目录下的文件列表 */ public function getDirFile($directory, $activepath = '', &$arr_file = array()) { if (!file_exists($directory)) { return false; } $fileArr = $dirArr = $parentArr = array(); $mydir = dir($directory); while(false !== $file = $mydir->read()) { $filesize = $filetime = $intro = ''; $filemine = 'file'; if($file != "." && $file != ".." && !is_dir("$directory/$file")) { @$filesize = filesize("$directory/$file"); @$filesize = format_bytes($filesize); @$filetime = filemtime("$directory/$file"); } if ($file == '.') { continue; } else if($file == "..") { if($activepath == "" || $activepath == $this->maxDir) { continue; } $parentArr = array( array( 'filepath' => preg_replace("#[\/][^\/]*$#i", "", $activepath), 'filename' => '上级目录', 'filesize' => '', 'filetime' => '', 'filemine' => 'dir', 'filetype' => 'dir2', 'icon' => 'file_topdir.gif', 'intro' => '(当前目录:'.$activepath.')', ), ); continue; } else if(is_dir("$directory/$file")) { if(preg_match("#^_(.*)$#i", $file)) continue; #屏蔽FrontPage扩展目录和linux隐蔽目录 if(preg_match("#^\.(.*)$#i", $file)) continue; $file_info = array( 'filepath' => $activepath.'/'.$file, 'filename' => $file, 'filesize' => '', 'filetime' => '', 'filemine' => 'dir', 'filetype' => 'dir', 'icon' => 'dir.gif', 'intro' => '', ); array_push($dirArr, $file_info); continue; } else if(preg_match("#\.(gif|png)#i",$file)) { $filemine = 'image'; $filetype = 'gif'; $icon = 'gif.gif'; } else if(preg_match("#\.(jpg|jpeg|bmp|webp)#i",$file)) { $filemine = 'image'; $filetype = 'jpg'; $icon = 'jpg.gif'; } else if(preg_match("#\.(svg)#i",$file)) { $filemine = 'image'; $filetype = 'svg'; $icon = 'jpg.gif'; } else if(preg_match("#\.(swf|fla|fly)#i",$file)) { $filetype = 'flash'; $icon = 'flash.gif'; } else if(preg_match("#\.(zip|rar|tar.gz)#i",$file)) { $filetype = 'zip'; $ic