model = Model("Source"); } public function pathInfo(){ $fileList = json_decode($this->in['dataArr'],true); if(!$fileList){ show_json(LNG('explorer.error'),false); } $result = array(); for ($i=0; $i < count($fileList); $i++){// 处理掉无权限和不存在的内容; $item = $fileList[$i]; if(isset($item['pathTrue']) && $item['pathTrue'] == '1'){ $item['path'] = kodIO::pathTrue($item['path']); // 相对路径获取处理; } if(!Action('explorer.auth')->can($item['path'],'show')) continue; $itemInfo = $this->itemInfo($item); if($itemInfo){$result[] = $itemInfo;} } if(count($fileList) == 1 && $result){ $result = $this->itemInfoMore($result[0]); } $data = !!$result ? $result : LNG('common.pathNotExists'); show_json($data,!!$result); } private function itemInfo($item){ $path = $item['path']; $type = _get($item,'type'); try{// 收藏或访问的io路径不存在情况报错优化; if($this->in['getChildren'] == '1'){ $result = IO::infoWithChildren($path); }else if($type == 'simple'){ $result = IO::info($path); }else{ $result = IO::infoFull($path); } }catch(Exception $e){ $result = false; } if(!$result) return false; // $canLink = Action('explorer.auth')->fileCanDownload($path); $canLink = Action('explorer.auth')->fileCan($path,'edit');//edit,share; 有编辑权限才能生成外链; if( $result['type'] == 'file' && $canLink){ $result['downloadPath'] = Action('explorer.share')->link($path); } $result = Action('explorer.list')->pathInfoParse($result,0,1); if($result['isDelete'] == '1'){unset($result['downloadPath']);} return $result; } public function pathInfoItem($path){ $pathInfo = IO::info($path); if(!$pathInfo) return false; return $this->itemInfoMore($pathInfo); } private function itemInfoMore($item){ $result = Model('SourceAuth')->authOwnerApply($item); $showMd5 = Model('SystemOption')->get('showFileMd5') != '0'; if($result['type'] != 'file') return $item; if($showMd5 && !_get($result,'fileInfo.hashMd5') && ($result['size'] <= 100*1024*1024 || _get($this->in,'getMore') || _get($this->in,'getChildren')) ){ $result['hashMd5'] = IO::hashMd5($result['path']); } $result = Action('explorer.list')->pathInfoMore($result); $result = Action('explorer.list')->fileInfoAddHistory($result); return $result; } public function desktopApp(){ $desktopApps = include(BASIC_PATH.'data/system/desktop_app.php'); $desktopApps['myComputer']['value'] = MY_HOME;// {source:home} 不指定打开文件夹,打开最后所在文件夹; if( !Action('explorer.listBlock')->pathEnable('my') ){ unset($desktopApps['myComputer']); } if($this->config['settings']['disableDesktopHelp'] == 1){ unset($desktopApps['userHelp']); } foreach ($desktopApps as $key => &$item) { if($item['menuType'] == 'menu-default-open'){ $item['menuType'] = 'menu-default'; } if(!KodUser::isRoot() && $item['rootNeed']){ unset($desktopApps[$key]); } };unset($item); show_json($desktopApps); } /** * 设置文档描述; */ public function setDesc(){ $maxLength = $GLOBALS['config']['systemOption']['fileDescLengthMax']; $msg = LNG('explorer.descTooLong').'('.LNG('explorer.noMoreThan').$maxLength.')'; $data = Input::getArray(array( 'path' => array('check'=>'require'), 'desc' => array('check'=>'length','param'=>array(0,$maxLength),'msg'=>$msg), )); $result = false; $info = IO::infoSimple($data['path']); if($info && $info['sourceID']){ $result = $this->model->setDesc($info['sourceID'],$data['desc']); } // $msg = !!$result ? LNG('explorer.success') : LNG('explorer.error'); show_json($data['desc'],!!$result); } /** * 设置文档描述; */ public function setMeta(){ $this->thumbClear(); $data = Input::getArray(array( 'path' => array('check'=>'require'), 'data' => array('check'=>'require'), )); $meta = json_decode($data['data'],true); if(!$meta || !is_array($meta)){ show_json(LNG('explorer.error'),false); } $info = IO::info($data['path']); $this->sourceSecretApply($meta,$info); if($info && $info['sourceID']){ foreach ($meta as $key => $value) { if( !$this->metaKeyCheck($key,$value,$info) ){ show_json("key error!",false); } $value = $value === '' ? null:$value; //为空则删除; $this->model->metaSet($info['sourceID'],$key,$value); } show_json(IO::info($data['path']),true); } show_json(LNG('explorer.error'),false); } private function metaKeyCheck($key,$value,$info){ static $metaKeys = false; if(!$metaKeys){ $metaKeys = array_keys($this->config['settings']['sourceMeta']); $metaKeys = array_merge($metaKeys,array( 'systemSort', // 置顶 'systemLock', // 编辑锁定 'systemLockTime', // 编辑锁定时间 )); } $isLock = _get($info,'metaInfo.systemLock') ? true:false; if($key == "systemLock" && $value && $isLock){ show_json(LNG('explorer.fileLockError'),false); } return in_array($key,$metaKeys); } // 文档密级处理; private function sourceSecretApply(&$meta,$pathInfo){ $key = 'user_sourceSecret'; if(!isset($meta[$key])) return; $sourceSecret = $meta[$key].''; unset($meta[$key]); // Model('SourceSecret')->clear(); //清除所有 debug; // Model("SystemOption")->set(array('sourceSecretList'=>'','sourceSecretMaxID'=>'')); // 检测支持: 是否开启密级;自己是否为系统管理员或密级管理者; 是否为部门文档; $systemOption = Model("SystemOption")->get(); if($pathInfo['targetType'] != 'group') return; if($systemOption['sourceSecret'] != '1') return; $allowUser = explode(',',$systemOption['sourceSecretSetUser']); if(!KodUser::isRoot() && !in_array(USER_ID,$allowUser)) return; $sourceID = $pathInfo['sourceID']; $model = Model('SourceSecret'); $find = $model->findByKey('sourceID',$sourceID); $data = array('sourceID'=>$sourceID,'typeID'=>$sourceSecret,'createUser'=>USER_ID); if($sourceSecret){ if($find){$model->update($find['id'],$data);} if(!$find){$model->insert($data);} }else{ if($find){$model->remove($find['id']);} } } // 清除文件缩略图 private function thumbClear(){ $data = Input::getArray(array( 'path' => array('check'=>'require'), 'clear' => array('default'=>0), )); if ($data['clear'] != '1') return; if (!IO::exist(IO_PATH_SYSTEM_TEMP)) show_json(LNG('explorer.success')); // 文件封面插件缩略图清理 $fileInfo = IO::info($data['path']); $fileThumbInfo = IO::infoFullSimple(IO_PATH_SYSTEM_TEMP . 'plugin/fileThumb'); if($fileThumbInfo && isset($fileThumbInfo['path'])) { $hasFind = false; $fileHash = KodIO::hashPath($fileInfo); $thumbList = array(250,600,1200,2000,3000,5000); // 缩略图尺寸 foreach ($thumbList as $width){ $coverName = "cover_{$fileHash}_{$width}.png"; $sourceID = IO::fileNameExist($fileThumbInfo['path'],$coverName); Cache::remove($coverName); if(!$sourceID){continue;} $hasFind = true; IO::remove(KodIO::make($sourceID),false); } if($hasFind){IO::setModifyTime($data['path'],time());} // 有缩略图清除,则更新最后修改时间,防止浏览器缓存 } // 删除元数据 $cacheKey = 'fileInfo.'.md5($fileInfo['path'].'@'.$fileInfo['size'].$fileInfo['modifyTime']); $fileID = _get($fileInfo,'fileID'); $fileID = _get($fileInfo,'fileInfo.fileID',$fileID); Cache::remove($cacheKey); if($fileInfo['sourceID']){Model('Source')->metaSet($fileInfo['sourceID'],'modifyTimeShow',time());} if(_get($fileInfo,'metaInfo.user_sourceCover')){ // 清空缩略图,包含清空文件设定的封面; Model('Source')->metaSet($fileInfo['sourceID'],'user_sourceCover'); } if($fileID){Model("File")->metaSet($fileID,'fileInfoMore',null);}; show_json(LNG('explorer.success')); } /** * 设置权限 */ public function setAuth(){ $result = false; $actionAllow = array( 'getData','clearChildren','getAllChildren','getGroupUser', 'getAllChildrenByUser','setAllChildrenByUser','chmod', ); $data = Input::getArray(array( 'path' => array('check'=>'require'), 'auth' => array('check'=>'json','default'=>array()), 'action'=> array('check'=>'in','default'=>'','param'=>$actionAllow), )); // local,chmod; if($data['action'] == 'chmod'){ $mode = intval($this->in['auth'],8); if($mode){$result = chmod_path($data['path'],$mode);} $msg = !!$result ? LNG('explorer.success') : LNG('explorer.error'); show_json($msg,!!$result); } $info = IO::info($data['path']); if( $info && $info['sourceID'] && $info['targetType'] == 'group'){//只能设置部门文档; $groupID = $info['targetID']; if($data['action'] == 'getData'){ $result = Model('SourceAuth')->getAuth($info['sourceID']); show_json($result); }else if($data['action'] == 'clearChildren'){ //清空所有子文件(夹)的权限; $result = Model('SourceAuth')->authClear($info['sourceID']); }else if($data['action'] == 'getAllChildren'){ //该文件夹下所有单独设置过权限的内容; 按层级深度排序-由浅到深(文件夹在前) $result = Model('SourceAuth')->getAllChildren($info['sourceID']); $result = array_page_split($result); show_json($result,true); }else if($data['action'] == 'getAllChildrenByUser'){ //该文件夹下所有针对某用户设置或权限的内容; $result = Model('SourceAuth')->getAllChildrenByUser($info['sourceID'],$this->in['userID']); $result = array_page_split($result); show_json($result,true); }else if($data['action'] == 'setAllChildrenByUser'){ //重置该文件夹下所有针对某用户设置权限的权限; $result = Model('SourceAuth')->setAllChildrenByUser($info['sourceID'],$this->in['userID'],$this->in['authID']); show_json($result ? LNG('explorer.success'): LNG('explorer.error'),true); }else if($data['action'] == 'getGroupUser'){ //部门成员在该部门的初始权限; 按权限大小排序 $result = Model('User')->listByGroup($groupID); foreach($result['list'] as $index=>$userInfo){ // $userInfo = Model('User')->getInfoSimpleOuter($userInfo['userID']); $groupAuth = array_find_by_field($userInfo['groupInfo'],'groupID',$groupID); $userInfo['groupAuth'] = $groupAuth ? $groupAuth['auth'] : false; $result['list'][$index] = $userInfo; } // 按权限高低排序; $result['list'] = array_sort_by($result['list'],'groupAuth.auth',true); show_json($result,true); }else{ $setAuth = $this->setAuthSelf($info,$data['auth']); $result = Model('SourceAuth')->setAuth($info['sourceID'],$setAuth); } } $msg = !!$result ? LNG('explorer.success') : LNG('explorer.error'); show_json($msg,!!$result); } // 设置权限.默认设置自己为之前管理权限; 如果只有自己则清空; private function setAuthSelf($pathInfo,$auth){ if(!$auth) return $auth; $selfAuth = _get($pathInfo,'auth.authInfo.id'); $authList = array(); foreach($auth as $item){ if( $item['targetID'] == USER_ID && $item['targetType'] == SourceModel::TYPE_USER){ continue; } $authList[] = $item; } if(!$authList || !$selfAuth) return $authList; $authList[] = array( 'targetID' => USER_ID, 'targetType'=> SourceModel::TYPE_USER, 'authID' => $selfAuth ); return $authList; } public function pathAllowCheck(&$path){ $notAllow = array('/', '\\', ':', '*', '?', '"', '<', '>', '|'); $db = $this->config['database'];// 文件文件夹名emoji是否支持处理; if(!isset($db['DB_CHARSET']) || $db['DB_CHARSET'] != 'utf8mb4'){ $path = preg_replace_callback('/./u',function($match){return strlen($match[0]) >= 4 ? '-':$match[0];},$path); } $name = trim(get_path_this($path)); $parse = KodIO::parse($path); if($parse['pathBase']){$name = trim(get_path_this($parse['param']));} if(!$name){return;} // 允许纯为空情况; 新建文件夹: {source:xxx}/ 允许该情况; $checkName = str_replace($notAllow,'_',$name); if($name != $checkName){ show_json(LNG('explorer.charNoSupport').implode(',',$notAllow),false); } $maxLength = $GLOBALS['config']['systemOption']['fileNameLengthMax']; if($maxLength && strlen($name) > $maxLength ){ show_json(LNG("common.lengthLimit")." (max=$maxLength)",false); } return; } public function mkfile(){ $this->pathAllowCheck($this->in['path']); $info = IO::info($this->in['path']); if($info && $info['type'] == 'file'){ //父目录为文件; show_json(LNG('explorer.success'),true,IO::pathFather($info['path'])); } $tplPath = BASIC_PATH.'static/others/newfile-tpl/'; $ext = get_path_ext($this->in['path']); $tplFile = $tplPath.'newfile.'.$ext; $content = _get($this->in,'content',''); if( isset($this->in['content']) ){ if( _get($this->in,'base64') ){ //文件内容base64; $content = base64_decode($content); } }else if(@file_exists($tplFile)){ $content = file_get_contents($tplFile); } $repeat = !empty($this->in['fileRepeat']) ? $this->in['fileRepeat']:REPEAT_RENAME; $result = IO::mkfile($this->in['path'],$content,$repeat); $errorLast = IO::getLastError(LNG('explorer.error')); $msg = !!$result ? LNG('explorer.success') : $errorLast; show_json($msg,!!$result,$result); } public function mkdir(){ $this->pathAllowCheck($this->in['path']); $repeat = !empty($this->in['fileRepeat']) ? $this->in['fileRepeat']:REPEAT_SKIP; $info = IO::info($this->in['path']); if($info && $info['type'] == 'file'){ //父目录为文件; show_json(LNG('explorer.success'),true,IO::pathFather($info['path'])); } $result = IO::mkdir($this->in['path'],$repeat); $errorLast = IO::getLastError(LNG('explorer.error')); $msg = !!$result ? LNG('explorer.success') : $errorLast; show_json($msg,!!$result,$result); } public function pathRename(){ $this->pathAllowCheck($this->in['newName']); $path = $this->in['path']; $this->taskCopyCheck(array(array("path"=>$path))); $result = IO::rename($path,$this->in['newName']); $errorLast = IO::getLastError(LNG('explorer.pathExists')); $msg = !!$result ? LNG('explorer.success') : $errorLast; show_json($msg,!!$result,$result); } public function pathDelete(){ $list = json_decode($this->in['dataArr'],true); $this->taskCopyCheck($list); $toRecycle = Model('UserOption')->get('recycleOpen'); if( _get($this->in,'shiftDelete') == '1' ){ $toRecycle = false; } $success=0;$error=0; foreach ($list as $val) { $result = Action('explorer.recycleDriver')->removeCheck($val['path'],$toRecycle); $result ? $success ++ : $error ++; } $code = $error === 0 ? true:false; $errorLast = IO::getLastError(LNG('explorer.removeFail')); $msg = $code ? LNG('explorer.removeSuccess') : $errorLast; if(!$code && $success > 0){ $msg = $success.' '.LNG('explorer.success').', '.$error.' '.$errorLast; } show_json($msg,$code); } // 从回收站删除 public function recycleDelete(){ $pathArr = false; if( _get($this->in,'all') ){ $recycleList = Model('SourceRecycle')->listData(); foreach ($recycleList as $key => $sourceID) { $recycleList[$key] = array("path"=>KodIO::make($sourceID)); } $this->taskCopyCheck($recycleList);//彻底删除: children数量获取为0,只能是主任务计数; }else{ $dataArr = json_decode($this->in['dataArr'],true); $this->taskCopyCheck($dataArr); $pathArr = $this->parseSource($dataArr); } Model('SourceRecycle')->remove($pathArr); Action('explorer.recycleDriver')->remove($pathArr); // 清空回收站时,重新计算大小; 一小时内不再处理; Model('Source')->targetSpaceUpdate(SourceModel::TYPE_USER,USER_ID); $cacheKey = 'autoReset_'.USER_ID; if(isset($this->in['all']) && time() - intval(Cache::get($cacheKey)) > 3600 * 10 ){ Cache::set($cacheKey,time()); $USER_HOME = KodIO::sourceID(MY_HOME); Model('Source')->folderSizeResetChildren($USER_HOME); Model('Source')->userSpaceReset(USER_ID); } show_json(LNG('explorer.success')); } //回收站还原 public function recycleRestore(){ $pathArr = false; if( _get($this->in,'all') ){ $recycleList = Model('SourceRecycle')->listData(); foreach ($recycleList as $key => $sourceID) { $recycleList[$key] = array("path"=>KodIO::make($sourceID)); } $this->taskCopyCheck($recycleList); }else{ $dataArr = json_decode($this->in['dataArr'],true); $this->taskCopyCheck($dataArr); $pathArr = $this->parseSource($dataArr); } Action('explorer.recycleDriver')->restore($pathArr); Model('SourceRecycle')->restore($pathArr); show_json(LNG('explorer.success')); } private function parseSource($list){ $result = array(); foreach ($list as $value) { $parse = KodIO::parse($value['path']); $thePath = $value['path'];// io路径;物理路径;协作分享路径处理保持不变; if($parse['type'] == KodIO::KOD_SOURCE){ $thePath = IO::getPath($value['path']); } $result[] = $thePath; } return $result; } public function pathCopy(){ Session::set(array( 'pathCopyType' => 'copy', 'pathCopy' => $this->in['dataArr'], )); show_json(LNG('explorer.copySuccess')); } public function pathCute(){ Session::set(array( 'pathCopyType' => 'cute', 'pathCopy' => $this->in['dataArr'], )); show_json(LNG('explorer.cuteSuccess')); } public function pathCopyTo(){ $this->pathPast('copy',$this->in['dataArr']); } public function pathCuteTo(){ $this->pathPast('cute',$this->in['dataArr']); } public function clipboard(){ if(isset($this->in['clear'])){ Session::set('pathCopy', json_encode(array())); Session::set('pathCopyType',''); return; } $clipboard = json_decode(Session::get('pathCopy'),true); if(!$clipboard){ $clipboard = array(); } show_json($clipboard,true,Session::get('pathCopyType')); } public function pathLog(){ $info = IO::info($this->in['path']); if(!$info['sourceID']){ show_json('path error',false); } $data = Model('SourceEvent')->listBySource($info['sourceID']); // 协作分享;路径数据处理; if($info['shareID']){ $shareInfo = Model('Share')->getInfo($info['shareID']); $userActon = Action('explorer.userShare'); foreach($data['list'] as $i=>$item){ if($item['sourceInfo']){ $data['list'][$i]['sourceInfo'] = $userActon->_shareItemeParse($item['sourceInfo'],$shareInfo); } if($item['parentInfo']){ $data['list'][$i]['parentInfo'] = $userActon->_shareItemeParse($item['parentInfo'],$shareInfo); } if(!is_array($item['desc'])){continue;} if(is_array($item['desc']['from'])){ $data['list'][$i]['desc']['from'] = $userActon->_shareItemeParse($item['desc']['from'],$shareInfo); } if(is_array($item['desc']['to'])){ $data['list'][$i]['desc']['to'] = $userActon->_shareItemeParse($item['desc']['to'],$shareInfo); } if(is_array($item['desc']['sourceID'])){ $data['list'][$i]['desc']['sourceID'] = $userActon->_shareItemeParse($item['desc']['sourceID'],$shareInfo); } } } show_json($data); } /** * 复制或移动 */ public function pathPast($copyType=false,$list=false){ if(!$copyType){ $copyType = Session::get('pathCopyType'); $list = Session::get('pathCopy'); if($copyType == 'cute'){ Session::set('pathCopy', json_encode(array())); Session::set('pathCopyType', ''); } } $list = json_decode($list,true); $list = is_array($list) ? $list : array(); if($copyType == 'copy'){ $list = $this->copyCheckShare($list); } $pathTo = $this->in['path']; if (count($list) == 0 || !$pathTo) { show_json(LNG('explorer.clipboardNull'),false); } ignore_timeout(0); $this->taskCopyCheck($list); Hook::trigger('explorer.pathCopyMove',$copyType,$list); $repeat = Model('UserOption')->get('fileRepeat'); $repeat = !empty($this->in['fileRepeat']) ? $this->in['fileRepeat'] :$repeat; $result = array();$errorList = array(); // 所有操作中,是否有重名覆盖的情况(文件,文件夹都算) $infoMore = array('hasExistAll'=>false,'pathTo'=>$pathTo,'listFrom'=>$list,'listTo'=>array()); for ($i=0; $i < count($list); $i++) { $thePath = $list[$i]['path']; $repeatType = $repeat; $ioInfo = IO::info($thePath); $driverTo = IO::init($this->in['path']); $hasExists = $driverTo->fileNameExist($driverTo->path,$ioInfo['name']); if($copyType == 'copy') { //复制到自己所在目录,则为克隆; $driver = IO::init($thePath); $father = $driver->getPathOuter($driver->pathFather($driver->path)); if(KodIO::clear($father) == KodIO::clear($pathTo) ){ $repeatType = REPEAT_RENAME_FOLDER; } $itemResult = IO::copy($thePath,$pathTo,$repeatType); }else{ $itemResult = IO::move($thePath,$pathTo,$repeatType); } // 复制/移动时; 所有内容是否存在文件夹已存在覆盖,文件已存在覆盖的情况; 存在时前端不支持撤销操作; if($hasExists){ if($ioInfo['type'] == 'file' && ($repeatType != REPEAT_RENAME && $repeatType != REPEAT_RENAME_FOLDER)){ $infoMore['hasExistAll'] = true; } if($ioInfo['type'] == 'folder' && $repeatType != REPEAT_RENAME_FOLDER){ $infoMore['hasExistAll'] = true; } } if(!$itemResult){$errorList[] = $thePath;continue;} $result[] = $itemResult; $infoMore['listTo'][] = array('path'=>$itemResult); } $code = $result ? true:false; $msg = $copyType == 'copy'?LNG('explorer.pastSuccess'):LNG('explorer.cutePastSuccess'); if(count($result) == 0){$msg = LNG('explorer.error');} if($errorList){$msg .= "(".count($errorList)." error)\n".IO::getLastError();} show_json($msg,$code,$result,$infoMore); } // 外链分享复制; private function copyCheckShare($list){ for ($i=0; $i < count($list); $i++) { $path = $list[$i]['path']; $pathParse= KodIO::parse($path); if($pathParse['type'] != KodIO::KOD_SHARE_LINK) continue; // 外链分享处理; 权限限制相关校验; 关闭下载--不支持转存; 转存数量限制处理; $info = Action('explorer.share')->sharePathInfo($path); if(!$info){ show_json($GLOBALS['explorer.sharePathInfo.error'], false); } if($info['option'] && $info['option']['notDownload'] == '1'){ show_json(LNG('explorer.share.noDownTips'), false); } $list[$i]['path'] = $info['path']; } return $list; } // 文件移动; 耗时任务; private function taskCopyCheck($list){ $list = is_array($list) ? $list : array(); $defaultID = 'copyMove-'.USER_ID.'-'.rand_string(8); $taskID = $this->in['longTaskID'] ? $this->in['longTaskID']:$defaultID; $task = new TaskFileTransfer($taskID,'copyMove'); $task->update(0,true);//立即保存, 兼容文件夹子内容过多,扫描太久的问题; for ($i=0; $i < count($list); $i++) { $task->addPath($list[$i]['path']); } } /** * 压缩下载 */ public function fileDownloadRemove(){ $path = Input::get('path', 'require'); $path = $this->pathCrypt($path,false); if(!$path || !IO::exist($path)) { show_json(LNG('common.pathNotExists'), false); } IO::fileOut($path,true); $dir = get_path_father($path); if(strstr($dir,TEMP_FILES)){ del_dir($dir); } } public function clearCache(){ $maxTime = 3600*24; $list = IO::listPath(TEMP_FILES); $list = is_array($list) ? $list : array('fileList'=>array(),'folderList'=>array()); $list = array_merge($list['fileList'],$list['folderList']); foreach($list as $item){ if(time() - $item['modifyTime'] < $maxTime) continue; if(is_dir($item['path'])){ del_dir($item['path']); }else{ del_file($item['path']); } } } /** * 多文件、文件夹压缩下载 * @return void */ public function zipDownload(){ $dataArr = json_decode($this->in['dataArr'],true); // 前端压缩处理; if($this->in['zipClient'] == '1'){ return show_json($this->zipDownloadClient($dataArr),true); } ignore_timeout(); $zipFolder = md5(json_encode(sort(array_to_keyvalue($dataArr,'','path')))); $zipCache = TEMP_FILES.$zipFolder.'/'; mk_dir($zipCache);file_put_contents($zipCache.'index.html',''); $zipPath = Cache::get($zipFolder); if($zipPath && IO::exist($zipPath) ){ return $this->zipDownloadStart($zipPath); } $zipPath = $this->zip($zipCache); Cache::set($zipFolder, $zipPath, 3600*6); $this->zipDownloadStart($zipPath); } private function zipDownloadStart($zipPath){ if(isset($this->in['disableCache']) && $this->in['disableCache'] == '1'){ if(!$zipPath || !IO::exist($zipPath)) return; IO::fileOut($zipPath,true); return; } show_json(LNG('explorer.zipSuccess'),true,$this->pathCrypt($zipPath)); } // 文件名加解密 public function pathCrypt($path, $en=true){ $pass = Model('SystemOption')->get('systemPassword').'encode'; return $en ? Mcrypt::encode($path,$pass) : Mcrypt::decode($path,$pass); } public function zipDownloadClient($dataArr){ $result = array(); foreach($dataArr as $itemZip){ $pathInfo = IO::info($itemZip['path']); $isFolder = $itemZip['type'] == 'folder'; $itemZipOut = array('path'=>'/'.$itemZip['name'],'folder'=>$isFolder); $itemZipOut['modifyTime'] = $pathInfo['modifyTime']; if(!$isFolder){ $itemZipOut['filePath'] = $itemZip['path']; $itemZipOut['size'] = $pathInfo['size']; $result[] = $itemZipOut;continue; } $result[] = $itemZipOut; $children = IO::listAllSimple($itemZip['path'],1); $result = array_merge($result, $children); } return $result; } /** * 压缩 * @param string $zipPath */ public function zip($zipPath=''){ ignore_timeout(); $dataArr = json_decode($this->in['dataArr'],true); $zipLimit = Model('SystemOption')->get('downloadZipLimit'); $task = $this->taskZip($dataArr); if($zipLimit && $zipLimit > 0){ $zipLimit = floatval($zipLimit) * 1024 * 1024 * 1024; $totalSize = intval($task->task['sizeTotal']); if($totalSize > $zipLimit){ $limitTips = '('.size_format($zipLimit).')'; show_json(LNG('admin.setting.downloadZipLimitTips').$limitTips,false); } } $fileType = Input::get('type', 'require','zip'); $repeat = Model('UserOption')->get('fileRepeat'); $repeat = !empty($this->in['fileRepeat']) ? $this->in['fileRepeat'] :$repeat; $zipFile = IOArchive::zip($dataArr, $fileType, $zipPath,$repeat); if($zipPath != '') return $zipFile; $info = IO::info($zipFile); $data = LNG('explorer.zipSuccess').LNG('explorer.file.size').":".size_format($info['size']); show_json($data,true,$zipFile); } private function taskZip($list){ $list = is_array($list) ? $list : array(); $defaultID = 'zip-'.USER_ID.'-'.rand_string(8); $taskID = $this->in['longTaskID'] ? $this->in['longTaskID']:$defaultID; $task = new TaskZip($taskID,'zip'); $task->update(0,true);//立即保存, 兼容文件夹子内容过多,扫描太久的问题; for ($i=0; $i < count($list); $i++) { $task->addPath($list[$i]['path']); } return $task; } private function taskUnzip($path){ $defaultID = 'unzip-'.USER_ID.'-'.rand_string(8); $taskID = $this->in['longTaskID'] ? $this->in['longTaskID']:$defaultID; $task = new TaskUnzip($taskID,'zip'); $task->addFile($path); } /** * 解压缩 */ public function unzip(){ ignore_timeout(); $data = Input::getArray(array( 'path' => array('check' => 'require'), 'pathTo' => array('check' => 'require'), 'unzipPart' => array('check' => 'require', 'default' => '-1') )); $repeat = Model('UserOption')->get('fileRepeat'); $repeat = !empty($this->in['fileRepeat']) ? $this->in['fileRepeat'] :$repeat; $this->taskUnzip($data['path']); $result = IOArchive::unzip($data['path'],$data['pathTo'],$data['unzipPart'],$repeat); show_json($result ? LNG('explorer.unzipSuccess'):LNG('explorer.error'),!!$result,$result); } /** * 查看压缩文件列表 */ public function unzipList(){ $data = Input::getArray(array( 'path' => array('check' => 'require'), 'index' => array('check' => 'require', 'default' => '-1'), 'download' => array('check' => 'require', 'default' => false), )); $this->taskUnzip($data['path']); $list = IOArchive::unzipList($data); $this->updateLastOpen($data['path']); show_json($list); } public function fileDownload(){ $this->in['download'] = 1; $this->fileOut(); } //输出文件 public function fileOut(){ $path = $this->in['path']; if(!$path) return; $isDownload = isset($this->in['download']) && $this->in['download'] == 1; $downFilename = !empty($this->in['downFilename']) ? $this->in['downFilename'] : false; if($isDownload && !Action('user.authRole')->authCanDownload()){ show_json(LNG('explorer.noPermissionAction'),false); } if($isDownload){Hook::trigger('explorer.fileDownload', $path);} Hook::trigger('explorer.fileOut',$path); if(isset($this->in['type']) && $this->in['type'] == 'image'){ $info = IO::info($path); $imageThumb = array('jpg','png','jpeg','bmp'); $width = isset($this->in['width']) ? intval($this->in['width']) :0; if($isDownload || !$width || $width >= 2000){ $this->updateLastOpen($path); } if($info['size'] >= 1024*200 && function_exists('imagecolorallocate') && in_array($info['ext'],$imageThumb) ){return IO::fileOutImage($path,$width);} return IO::fileOut($path,$isDownload,$downFilename); // 不再记录打开时间; } $this->fileOutUpdate($path,$isDownload,$downFilename); } /* 相对某个文件访问其他文件; 权限自动处理;支持source,分享路径,io路径,物理路径; path={source:1138926}/&add=images/as.png; path={source:1138926}/&add=as.png path={shareItem:123}/1138934/&add=images/as.png 相对路径支持;local,io,(source),shareLink,shareItem[local,io,(source)] /a/b/.././c/../1.txt => /a/1.txt; */ public function fileOutBy(){ if(!$this->in['path']) return; // 拼接转换相对路径; $add = kodIO::pathUrlClear(rawurldecode($this->in['add'])); $parse = kodIO::parse($this->in['path']); $allow = array('',false,kodIO::KOD_IO,kodIO::KOD_USER_DRIVER,kodIO::KOD_SHARE_LINK); if(in_array($parse['type'],$allow)){ $distPath = kodIO::pathTrue($parse['path'].'/../'.$add); $distInfo = IO::info($distPath); }else{//KOD_SOURCE KOD_SHARE_ITEM(source,) $info = IO::info($parse['path']); if($parse['type'] == kodIO::KOD_SOURCE){ $level = Model("Source")->parentLevelArray($info['parentLevel']); $pathRoot = '{source:'.$level[0].'}'; }else if($parse['type'] == kodIO::KOD_SHARE_ITEM){ $pathArr = explode('/',trim($parse['path'],'/')); $pathRoot = $pathArr[0]; $shareInfo = Model('Share')->getInfo($parse['id']); // source路径内部协作分享; if($shareInfo['sourceID']){$pathRoot = $pathRoot.'/'.$shareInfo['sourceID'];} } $displayPathArr = explode('/',trim($info['pathDisplay'],'/'));array_shift($displayPathArr); $displayPath = $pathRoot.'/'.implode('/',$displayPathArr); $distPath = kodIO::pathTrue($displayPath.'/../'.$add); $distInfo = IO::infoFullSimple($distPath); } // pr($distPath,$distInfo,$parse,[$pathRoot,$displayPath,$info,$shareInfo]);exit; if(!$distInfo || $distInfo['type'] != 'file'){ return show_json(LNG('common.pathNotExists'),false); } if(isset($this->in['type']) && $this->in['type'] == 'getTruePath'){ show_json($distInfo['path'],true); } ActionCall('explorer.auth.canView',$distInfo['path']);// 再次判断新路径权限; Hook::trigger('explorer.fileOut', $distInfo['path']); $this->fileOutUpdate($distInfo['path'],false); } public function fileOutUpdate($path,$isDownload=false,$downFilename=''){ $this->updateLastOpen($path); IO::fileOut($path,$isDownload,$downFilename); } // 打开文档,更新最后打开时间 public function updateLastOpen($path){ static $LAST_PATH = false; if($LAST_PATH && $LAST_PATH == trim($path,'/')){return;} $LAST_PATH = trim($path,'/'); // 一次请求只处理一次 $driver = IO::init($path); if($driver->pathParse['type'] != KodIO::KOD_SOURCE) return; if(isset($_SERVER['HTTP_RANGE'])){ // 分片下载, 不是从头开始不再记录; $match = preg_match('/bytes=\s*(\d+)-(\d*)[\D.*]?/i',$_SERVER['HTTP_RANGE'],$matches); if($match && $matches[1] && intval($matches[1]) < 10){return;} } $sourceInfo = $this->model->sourceInfo($driver->pathParse['id']); if(!$sourceInfo || $sourceInfo['isDelete'] == '1' || $sourceInfo['isFolder'] == '1' || $sourceInfo['size'] == 0){return;} if($sourceInfo['targetType'] != SourceModel::TYPE_USER && $sourceInfo['targetType'] != SourceModel::TYPE_GROUP){return;} $this->model->where(array('sourceID'=>$sourceInfo['sourceID']))->save(array('viewTime' => time())); //write_log($this->in['URLrouter'].'; path='.$path.'; range='.($matches ? $matches[1]:''),'test'); } //通用保存 public function fileSave(){ if(!$this->in['path'] || !$this->in['path']) return; $result = IO::setContent($this->in['path'],$this->in['content']); Hook::trigger("explorer.fileSaveStart",$this->in['path']); show_json($result,!!$result); } //通用预览 public function fileView(){ } //通用缩略图 public function fileThumb(){ Hook::trigger("explorer.fileThumbStart",$this->in['path']); } }