This page lists files in the current directory. You can view content, get download/execute commands for Wget, Curl, or PowerShell, or filter the list using wildcards (e.g., `*.sh`).
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/api.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerApi extends Controller{
function __construct(){
parent::__construct();
}
/**
* 通用文件预览方案
* image,media,cad,office,webodf,pdf,epub,swf,text
* 跨域:epub,pdf,odf,[text];
* @return [type] [description]
*/
public function view(){
if(!isset($this->in['path'])){
show_tips(LNG('explorer.share.errorParam'));
}
$this->checkAccessToken();
$this->setIdentify();
}
private function setIdentify(){
if(!Session::get('accessPlugin')){
Session::set('accessPlugin', 'ok');
}
}
public function checkAccessToken(){
$config = Model('Plugin')->getConfig('fileView');
if(!$config || !$config['apiKey']){
show_tips('fileView not open ,or apiKey is empty!');
}
$timeTo = isset($this->in['timeTo'])?intval($this->in['timeTo']):'';
$token = md5($this->in['path'].$timeTo.$config['apiKey']);
if($token != $this->in['token']){
show_tips('token ' . LNG('common.error'));
}
if($timeTo != '' && $timeTo <= time()){
show_tips('token ' . LNG('common.expired'));
}
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/attachment.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 通用图片附件存储模块;
* 用于文章,日志,聊天,评论等附件上传;
*
* 上传和内容关联为异步关系;
* 1. 附件临时存储池: 所有上层都自动存储到临时附件区域; 定期清理创建时间超过24h的临时文件;
* 2. 存储关联对象(文章,日志,聊天,评论等): 文章或内容发布后根据id关联文档,文档转存到附件区;
* 3. 对象内容图片处理: 外链图片下载到本地; 图片去本地连接;
* 4. 根据对象清理附件: 文章删除,则删除对应关联的附件资源; meta: linkArticle=>id; linkMessage=>id;
*
* 处理问题: 避免文章编辑过程中上传文件失联,没有地方可以删除(未关联的内容存储在临时存储池,定期清除;)
* 外链图片下载到本地;域名白名单;
*/
class explorerAttachment extends Controller{
function __construct(){
parent::__construct();
//去除svg; 避免xxs攻击;
$this->imageExt = array('png','jpg','jpeg','gif','webp','bmp','ico');
}
// 上传; 扩展名限制jpg,jpeg,png,ico
public function upload(){
$ext = get_path_ext(Uploader::fileName());
if(!in_array($ext,$this->imageExt)){
show_json("only support image",false);
}
$this->in['name'] = date("YmdHi").rand_string(6).'.'.$ext;
$this->in['path'] = KodIO::systemFolder('attachmentTemp/');
Action('explorer.upload')->fileUpload();
}
// 文档评论;
public function commentLink($id){
$where = array('commentID'=>$id);
$data = Model("Comment")->where($where)->find();
if(!$data) return;
$contentNew = $this->linkTarget($id,$data['content'],'comment');
// 内容有解析变更,则替换;
if($contentNew && $contentNew != $data['content']){
Model("Comment")->where($where)->save(array('comment'=>$contentNew));
}
}
public function commentClear($id){
$this->clearTarget($id,'comment');
}
public function noticeLink($id){
$model = Model("SystemNotice");
$data = $model->listData($id);
if(!$data) return;
$contentNew = $this->linkTarget($id,$data['content'],'notice');
// 内容有解析变更,则替换;
if($contentNew && $contentNew != $data['content']){
$model->update($id,array('comment'=>$contentNew));
}
}
public function noticeClear($id){
$this->clearTarget($id,'notice');
}
// 自动清理24小时未转移的临时文件;
public function clearCache(){
$timeStart = time() - 3600*24;//1天前未关联的临时文件区域;
$tempFolder = KodIO::systemFolder('attachmentTemp/');
$where = array(
'parentID' => KodIO::sourceID($tempFolder),
'createTime' => array('<',$timeStart),
);
$sourceArr = Model("Source")->where($where)->select();
$sourceArr = array_to_keyvalue($sourceArr,'','sourceID');
if(!$sourceArr) return;
foreach($sourceArr as $sourceID){
Model('Source')->remove($sourceID,false);
}
}
// 解析内容匹配图片; 关联文件到目标对象;
public function linkTarget($id,$content,$targetType){
$result = $this->parseImage($content);
if(!$result['sourceArr']) return $result['content'];
$metaKey = 'attachment_'.$targetType;
$storePath = KodIO::systemFolder('attachment/'.date("Ym/d/"));
$sourceList = Model('Source')->sourceListInfo($result['sourceArr']);
foreach ($sourceList as $sourceInfo){
if($sourceInfo['targetType'] != 'system') continue;
if($sourceInfo['metaInfo'] && isset($sourceInfo['metaInfo'][$metaKey])) continue;
IO::move($sourceInfo['path'],$storePath,REPEAT_REPLACE);
// write_log('move from='.$sourceInfo['path'].'; to='.$storePath,'attachment');
Model('Source')->metaSet($sourceInfo['sourceID'],$metaKey,$id);
}
return $result['content'];
}
// 清除目标对象关联的附件;
public function clearTarget($id,$targetType){
$metaKey = 'attachment_'.$targetType;
$where = array('key'=>$metaKey,'value'=>$id);
$sourceArr = Model('io_source_meta')->where($where)->select();
$sourceArr = array_to_keyvalue($sourceArr,'','sourceID');
if(!$sourceArr) return true;
// write_log($sourceArr,'attachment');
foreach ($sourceArr as $sourceID){
Model('Source')->remove($sourceID,false);
}
}
// 解析图片链接到sourceID; 如果有外链需要转入的替换内容$content;
private function parseImage($content){
preg_match_all("/<img.*?src=[\'|\"](.*?)[\'|\"].*?[\/]?>/i",$content,$imageArr);
if(!$imageArr) return array("sourceArr"=>false,'content'=>$content);
$sourceArr = array();
$replace = array();
for($i = 0; $i < count($imageArr[1]); $i++) {
$imageSrc = $imageArr[1][$i];
$imageHtml = $imageArr[0][$i];
$imageParse = $this->parseLink($imageSrc);
if($imageParse['sourceID']) {
$sourceArr[] = $imageParse['sourceID'];
}
//url解析替换;
if($imageParse['linkNew'] && $imageSrc != $imageParse['linkNew']){
$replace[$imageHtml] = str_replace($imageSrc,$imageParse['linkNew'],$imageHtml);
}
}
$sourceArr = array_unique($sourceArr);
$contentNew = str_replace(array_keys($replace),array_values($replace),$content);
return array("sourceArr"=>$sourceArr,'content'=>$contentNew);
}
private function parseLink($link){
$local = array(
'http://127.0.0.1/',
'https://127.0.0.1/',
'//127.0.0.1/',
'http://localhost/',
'https://localhost/',
'//localhost/',
);
$linkNew = str_replace($local,'/',$link);
if($this->proxyNeed($link)){ //外部图片链接转为内部链接;
// $linkNew = $this->fileProxy($link);
}
preg_match("/explorer\/share\/file(&|&)hash=([0-9a-zA-z_-]+)/",$link,$hash);
$sourceID = '';
if($hash){ // 外站kod的url自动处理;
$pass = Model('SystemOption')->get('systemPassword');
$path = Mcrypt::decode($hash[2],$pass);
$ioSource = KodIO::parse($path);
if($ioSource['type'] == KodIO::KOD_SOURCE){
$sourceID = $ioSource['id'];
}
}
return array(
'linkNew' => $linkNew == $link ? '' : $linkNew,
'sourceID' => $sourceID,
);
}
// 外链防跨站资源; 自动远程下载;
private function fileProxy($link){
$saveFile = TEMP_FILES.'fileProxy_download_'.md5($link);
$result = Downloader::start($link,$saveFile);
if(!$result['code']) return $link;
$ext = get_path_ext($link);
if(!in_array($ext,$this->imageExt)){
$ext = 'jpg';
}
$filename = date("YmdHi").rand_string(6).'.'.$ext;
$storePath = KodIO::systemFolder('attachmentTemp/');
$file = IO::move($saveFile,$storePath,REPEAT_REPLACE);
IO::rename($file,$filename);
return Action('explorer.share')->link($file);
}
private function proxyNeed($link){
$parseUrl = parse_url($link);
if(!$parseUrl['host']) return false;
$hostAllow = array(
'douban.com','doubanio.com',
'qq.com',
);
foreach ($hostAllow as $domain){
if(substr($parseUrl['host'],-strlen($domain)) == $domain) return true;
}
return false;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/auth.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 文档操作权限旁路拦截;
*
* 如下是配置单个文档操作,统一path参数进行权限检测
* 其他拦截:path为虚拟目录只支持列表模式 explorer.list.path;
*/
class explorerAuth extends Controller {
private $actionPathCheck;
function __construct() {
parent::__construct();
$this->isShowError = true; //检测时输出报错;
$this->actionPathCheck = array(
'show' => array("explorer.list"=>'path,listAll'),
'view' => array(
'explorer.index'=>'fileOut,fileOutBy,unzipList,pathLog,fileView,fileThumb',
'explorer.editor' =>'fileGet'
),
'download' => array('explorer.index'=>'fileDownload,zipDownload,fileDownloadRemove'),// 下载/复制;下载/复制/文件预览打印
'upload' => array(
'explorer.upload' =>'fileUpload,serverDownload',
'explorer.index' =>'mkdir,mkfile',
),
'edit' => array(
'explorer.index' =>'mkdir,mkfile,setDesc,fileSave,pathRename,pathPast,pathCopyTo,pathCuteTo,setMeta',
'explorer.editor' =>'fileSave'
),
// 'remove' => array('explorer.index'=>'pathDelete'), //批量中处理
'share' => array('explorer.userShare'=>'add'),// get,edit,del 在userShare中自行判断(允许协作者(拥有者时)修改协作成员及权限)
'comment' => array('comment.index'=>''),
'event' => array('explorer.index'=>'pathLog'),
'root' => array('explorer.index'=>'setAuth'),
);
$this->actionCheckSpace = array(//空间大小检测
'explorer.upload' => 'fileUpload,serverDownload',
'explorer.index' => 'mkdir,mkfile,fileSave,pathPast,pathCopyTo,pathCuteTo,unzip',
'explorer.editor' => 'fileSave',
'explorer.share' => 'fileUpload',
);
Hook::bind('SourceModel.createBefore','explorer.auth.checkSpaceOnCreate');
}
// 文档操作权限统一拦截检测
public function autoCheck(){
$theMod = strtolower(MOD);
$theAction = strtolower(ACTION);
if($theMod !== 'explorer') return;
$this->targetSpaceCheck();//空间大小检测
Action('explorer.listGroup')->pathRootCheck($theAction);
Action('explorer.autoPathParse')->parseAuto();
// 多个请求或者包含来源去向的,分别进行权限判别;
switch ($theAction) {//小写
//自行判断权限,兼容文件关联附件获取信息情况;
// case 'explorer.index.pathinfo':$this->checkAuthArray('show');break;
case 'explorer.index.zip':$this->checkAuthArray('edit');break;
case 'explorer.index.zipdownload':$this->checkAuthArray('download');break;
case 'explorer.index.unzip':
$this->canRead($this->in['path']);
$this->canWrite($this->in['pathTo']);
break;
case 'explorer.index.pathdelete':$this->checkAuthArray('remove');break;
case 'explorer.index.pathcopy':$this->checkAuthArray('download');break;
case 'explorer.index.pathcute':
$this->checkAuthArray('remove');
break;
case 'explorer.index.pathcopyto':
$data = json_decode($this->in['dataArr'],true);
if(!is_array($data)){
return $this->errorMsg('param error:dataArr!');
}
// $this->checkAuthArray('download');
// 来源文档权限检测: 有编辑权限或者下载权限;
$checkAction = 'download'; // 没有下载权限,有复制粘贴权限时,允许从其他地方复制后粘贴(检测读取权限);
$seleCanDownload = Action("user.authRole")->authCanDownload();
if(!$seleCanDownload){$checkAction = 'view';}
$this->isShowError = false;$errorNum = 0;
foreach ($data as $item) {
$result = $this->can($item['path'],$checkAction);
if(!$result){$errorNum++;}
}
$this->isShowError = true;
if($errorNum){
$msg = $this->lastError ? $this->lastError : LNG('explorer.noPermissionAction');
$code = $this->lastErrorCode ? $this->lastErrorCode : 1007;
$this->errorMsg($msg,$code);
}
$this->canWrite($this->in['path']);
break;
case 'explorer.index.pathcuteto':
$this->checkAuthArray('remove');
$this->canWrite($this->in['path']);
break;
case 'explorer.upload.serverdownload':
if($this->in['path']){
$this->canWrite($this->in['path']);
}
break;
default:
//直接检测;定义在actionPathCheck中的方法;参数为path,直接检测
$actionType = $this->actionParse();
if(isset($actionType[$theAction])){
$authTypeArr = $actionType[$theAction];
$errorNum = 0; // 一个控制器对应多个权限点时; 所有都失败了才算失败;一个成功就算成功;
$this->isShowError = false;
for ($i=0; $i < count($authTypeArr); $i++) {
$result = $this->can($this->in['path'],$authTypeArr[$i]);
if(!$result){$errorNum++;}
}
$this->isShowError = true;
if($errorNum == count($authTypeArr)){
$msg = $this->lastError ? $this->lastError : LNG('explorer.noPermissionAction');
$code = $this->lastErrorCode ? $this->lastErrorCode : 1007;
$this->errorMsg($msg,$code);
}
}
break;
}
}
public function targetSpaceCheck(){
$actions = array();
foreach ($this->actionCheckSpace as $controller => $stActions) {
$stActions = explode(',',trim($stActions,','));
foreach ($stActions as $action) {
$actions[] = strtolower($controller.'.'.$action);
}
}
if(!in_array(strtolower(ACTION),$actions)) return;
if(!$this->spaceAllow($this->in['path'])){
show_json(LNG('explorer.spaceIsFull'),false);
}
}
public function spaceAllow($path){
$parse = KodIO::parse($path);
if($parse['isTruePath'] != true) return true;
if($parse['driverType'] == 'io') return true;
$info = IO::infoAuth($parse['pathBase']);//目标存储;
// 目标在回收站中: 不支持保存/上传/远程下载/粘贴/移动到此/新建文件/新建文件夹;
$fromDav = _get($GLOBALS,'requestFrom') == 'webdav';
if($info['isDelete'] == '1' && !$fromDav){
$msg = $info['type'] == 'file' ? LNG('explorer.pathInRecycleFile') : LNG("explorer.pathInRecycle");
show_json($msg,false);
}
$space = Action("explorer.list")->targetSpace($info);
if(!$space || $space['sizeMax']==0 ) return true; // 没有大小信息,或上限为0则放过;
$result = $space['sizeMax'] > $space['sizeUse'];
if(!$result){$this->lastError = LNG('explorer.spaceIsFull');}
return $result;
}
public function checkSpaceOnCreate($sourceInfo){
$space = false;
if($sourceInfo['targetType'] == SourceModel::TYPE_GROUP){
$space = $this->space('group',$sourceInfo['targetID']);
}else if($sourceInfo['targetType'] == SourceModel::TYPE_USER){
$space = $this->space('user',$sourceInfo['targetID']);
}
if(!$space || $space['sizeMax']==0 ) return true; // 没有大小信息,或上限为0则放过;
if($space['sizeMax'] <= $space['sizeUse']+ $sourceInfo['size'] ){
show_json(LNG('explorer.spaceIsFull'),false);
}
}
// 用户空间占用集中处理;
public function space($targetType,$targetID){
if($targetType == 'user'){//空间追加处理;
$target = Model('User')->getInfo($targetID);
}else{
$target = Model('Group')->getInfo($targetID);
}
$target['sizeUse'] = (!$target['sizeUse'] || $target['sizeUse'] <= 0 ) ? 0 : intval($target['sizeUse']);
$result = array(
'targetType' => $targetType,
'targetID' => $targetID,
'targetName' => $target['name'],
"sizeMax" => floatval($target['sizeMax'])*1024*1024*1024,
"sizeUse" => $target['sizeUse'],
);
$result = Hook::filter("explorer.targetSpace",$result);
return $result;
}
// 外部获取文件读写权限; Action("explorer.auth")->fileCanRead($path);
public function fileCanRead($file){
if($this->fileIsShareLink($file)){return $this->fileCan($file,'view');}
if(!ActionCall('user.authRole.authCanRead')) return false;
return $this->fileCan($file,'view');
}
public function fileCanDownload($file){
if($this->fileIsShareLink($file)){return $this->fileCan($file,'download');}
if(!ActionCall('user.authRole.authCanRead')) return false;
return $this->fileCan($file,'download');
}
public function fileCanWrite($file){
if($this->fileIsShareLink($file)){return $this->fileCan($file,'edit');}
if(!ActionCall('user.authRole.authCanEdit')) return false;
return $this->fileCan($file,'edit');
}
private function fileIsShareLink($file){
return strpos($file,'{shareItemLink:') === 0 ? true:false;
}
public function fileCan($file,$action){
if(request_url_safe($file)) return true;
$this->isShowError = false;
$result = $this->can($file,$action);
$this->isShowError = true;
return $result;
}
/**
* 检测文档权限,是否支持$action动作
* 目录解析:拦截只支持列目录,但当前方法为其他操作的
* 获取目录信息:自己的文档,则放过
*
* 权限判断:
* 1. 是不是:是不是自己的文档;是的话则跳过权限检测
* 2. 能不能:
* a. 是我所在的部门的文档:则通过权限&动作判别
* b. 是内部协作分享给我的:检测分享信息,通过权限&动作判别
* c. 其他情况:一律做权限拦截;
*
* 操作屏蔽:remove不支持根目录:用户根目录,部门根目录,分享根目录;
*/
public function can($path,$action){
if(!$path || !is_string($path)){return false;}
$isRoot = KodUser::isRoot();
$parse = KodIO::parse($path);
$ioType = $parse['type'];
if($ioType == KodIO::KOD_SHARE_LINK){
$pathInfo = Action('explorer.share')->sharePathInfo($path);
$shareInfo = Action('explorer.share')->shareInfoLast();
if ($pathInfo && $shareInfo) {
// if(in_array($action,array('view','show'))) return true;
if($action == 'show') return true;
if($action == 'view' && _get($shareInfo,'options.notView') !='1' ) return true;
if($action == 'download' && _get($shareInfo,'options.notDownload') !='1' ) return true;
if($action == 'edit' && _get($shareInfo,'options.canEditSave') == '1' ){
if(Model('SystemOption')->get('shareLinkAllowEdit') == '0'){ // 全局开关;
return $this->errorMsg(LNG('explorer.pathNotSupport'),1108);
}
return true;
}
}
return $this->errorMsg(LNG('explorer.pathNotSupport'),1108);
}
if(!$isRoot && !Action('user.authRole')->canCheckRole($action)){
return $this->errorMsg(LNG('explorer.noPermissionAction'),1021);
}
if($ioType == KodIO::KOD_SHARE_OUTER){ // 外部分享内容; 权限在内容自行处理;
$driver = IO::init($path);
if($driver->allowAction($action)){return true;}
return $this->errorMsg(IO::getLastError(LNG('explorer.noPermissionAction')),1021);
}
// 物理路径 io路径拦截;只有管理员且开启了访问才能做相关操作;
if( $ioType == KodIO::KOD_IO || $ioType == false ){
if( request_url_safe($path) ) return $action == 'view';
// 允许管理存储,即可访问系统回收站及挂载的存储.
$pathCanRead = Action('user.authRole')->authCan('admin.storage.edit');
if($pathCanRead && $this->config["ADMIN_ALLOW_IO"]) return true;
if($pathCanRead && $parse['id'] == 'systemRecycle') return true;
return $this->errorMsg(LNG('explorer.pathNotSupport'),1001);
}
//个人挂载目录;跨空间移动复制根据身份处理;
if( $ioType == KodIO::KOD_USER_DRIVER ) return true;
//不支持删除自己的桌面
if($action == 'remove'){
if(trim($path,'/') == trim(MY_DESKTOP,'/')){
return $this->errorMsg(LNG('explorer.desktopDelError'),1100);
}
if(trim($path,'/') == trim(MY_HOME,'/')){
return $this->errorMsg(LNG('explorer.pathNotSupport'),1100);
}
}
// 纯虚拟路径只能列表; 不支持其他任何操作;
if( $this->pathOnlyShow($path) ){
if($action == 'show') return true;
return $this->errorMsg(LNG('explorer.pathNotSupport'),1002);
}
//分享内容;分享子文档所属分享判别,操作分享权限判别;
if( $ioType == KodIO::KOD_SHARE_ITEM){
return $this->checkShare($parse['id'],trim($parse['param'],'/'),$action);
}
$pathInfo = IO::infoAuth($parse['pathBase']);
Hook::trigger("explorer.auth.can",$pathInfo,$action);
// 个人私密空间是否登录检测;
if($pathInfo && isset($pathInfo['sourceID']) && $pathInfo['targetType'] == 'user'){
$errorMsg = Action('explorer.listSafe')->authCheck($pathInfo,$action);
if($errorMsg){return $this->errorMsg($errorMsg,1101);}
}
//上层文件夹是否需要密码;
if($pathInfo && isset($pathInfo['sourceID'])){
$errorMsg = Action('explorer.listPassword')->authCheck($pathInfo,$action);
if($errorMsg){return $this->errorMsg($errorMsg,1102);}
}
// source 类型; 新建文件夹 {source:10}/新建文件夹; 去除
//文档类型检测:屏蔽用户和部门之外的类型;
if($this->allowRootSourceInfo($pathInfo)) return true;
$targetType = $pathInfo['targetType'];
// if(!$pathInfo) return true;
if(!$pathInfo){//不存在,不判断文档权限;
return $this->errorMsg(LNG('common.pathNotExists'),0);
}
if( $targetType != 'user' && $targetType != 'group' ){
return $this->errorMsg(LNG('explorer.noPermissionAction'),1003);
}
//个人文档;不属于自己
if( $targetType == 'user' && $pathInfo['targetID'] != USER_ID ){
return $this->errorMsg(LNG('explorer.noPermissionAction'),1004);
}
//部门文档:权限拦截;会自动匹配权限;我在的部门会有对应权限
if($targetType == 'group'){
$auth = $pathInfo['auth']['authValue'];
return $this->checkAuthMethod($auth,$action);
}
// 删除操作:拦截根文件夹;用户根文件夹,部门根文件夹
if( $pathInfo['parentID'] == '0' && $action=='remove' ){
return $this->errorMsg(LNG('explorer.noPermissionAction'),1100);
}
return true;
}
public function allowRootSourceInfo($pathInfo){
$isRoot = KodUser::isRoot();
if($isRoot && $this->config["ADMIN_ALLOW_SOURCE"]) return true;
if($isRoot && $pathInfo && $pathInfo['pathType'] == '{systemRecycle}') return true;
return false;
}
// 路径类型中: 检测目录是否可操作(属性,重命名,新建上传等); 纯虚拟路径只能列表;
public function pathOnlyShow($path){
$parse = KodIO::parse($path);
$truePath = array( // 可以操作的目录类型;
KodIO::KOD_IO,
KodIO::KOD_SOURCE,
KodIO::KOD_SHARE_ITEM,
);
$canAction = in_array($parse['type'],$truePath);
return $canAction? false:true;
}
private function errorMsg($msg,$code=false){
if($this->isShowError){
return show_json($msg,false,$code);
}
$this->lastError = $msg;
$this->lastErrorCode = $code;
return false;
}
public function getLastError(){return $this->lastError;}
public function canView($path){return $this->can($path,'view');}
public function canRead($path){return $this->can($path,'download');}
public function canWrite($path){return $this->can($path,'edit');}
private function checkAuthArray($action){
$data = json_decode($this->in['dataArr'],true);
if(!is_array($data)){
return $this->errorMsg('param error:dataArr!');
}
foreach ($data as $item) {
$this->can($item['path'],$action);
}
}
/**
* 根据权限值判别是否允许该动作
* $method: view,show,... AuthModel::authCheckShow...
*/
private function checkAuthMethod($auth,$method){
if(KodUser::isRoot() && $this->config["ADMIN_ALLOW_SOURCE"]) return true;
$auth = intval($auth);
if(!$auth || $auth == 0){
return $this->errorMsg(LNG('explorer.noPermissionAction'),1005);
}
//某文档有权限,打通上层文件夹通路;
if($method == 'show' && $auth === -1) return true;
$method = strtoupper(substr($method,0,1)).substr($method,1);
$method = 'authCheck'.$method;
$allow = Model('Auth')->$method($auth);
if(!$allow){
return $this->errorMsg(LNG('explorer.noPermissionAction'),1006);
}
return true;
}
/**
* 分享检测:
* 1. 分享存在;文档存在;
* 2. 文档属于该分享或该分享的子目录
* 2. 且自己在分享目标中; 权限不等于0 说明自己在该分享中;
* 3. 权限动作检测
*
* 分享根文件夹不支持删除操作;
*/
public function checkShare($shareID,$sourceID,$method){
$shareInfo = Model('Share')->getInfoAuth($shareID);
$sharePath = $shareInfo['sourceID'].'';
if(!$shareInfo || !$shareInfo['sourceInfo'] ){
return $this->errorMsg(LNG('explorer.share.notExist'));
}
if( $sharePath == $sourceID && $method =='remove' ){
return $this->errorMsg("source share root can't remove !");
}
// 自己协作分享的内容; 权限同自己拥有的权限;
if($shareInfo['userID'] == USER_ID){
$sourceInfo = $shareInfo['sourceInfo'];
if( $sourceInfo['targetType'] == 'user' && $sourceInfo['targetID'] == USER_ID ){
return Action('user.authRole')->canCheckRole($method);
}
if(!$shareInfo['sourceInfo']['auth']){ // 自己内部协作分享 io路径(拥有后台存储管理权限的角色)
return Action('explorer.authUser')->can($shareInfo['sourcePath'],$method,$shareInfo['userID']);
}
return $this->checkAuthMethod($shareInfo['sourceInfo']['auth']['authValue'],$method);
}
// 分享时间处理;
$timeout = intval(_get($shareInfo,'options.shareToTimeout',0));
if($timeout > 0 && $timeout < time()){
return $this->errorMsg(LNG('explorer.share.expiredTips'));
}
// 关闭协作分享的;
if($shareInfo['isShareTo'] == '0'){
return $this->errorMsg(LNG('explorer.share.notExist').'[status=0]');
}
// 内部协作分享有效性处理: 当分享者被禁用,没有分享权限,所在文件不再拥有分享权限时自动禁用外链分享;
if(!Action('explorer.authUser')->canShare($shareInfo)){
$userInfo = Model('User')->getInfoSimpleOuter($shareInfo['userID']);
$tips = '('.$userInfo['name'].' - '.LNG('common.noPermission').')';
return $this->errorMsg(LNG('explorer.share.notExist').$tips);
}
// 物理路径,io路径;
if($shareInfo['sourceID'] == '0'){
$sharePath = KodIO::clear($shareInfo['sourcePath']);
$thisPath = KodIO::clear($shareInfo['sourcePath'].$sourceID);
if(substr($thisPath,0,strlen($sharePath)) != $sharePath) return false;
return $this->checkAuthMethod($shareInfo['auth']['authValue'],$method);
}
if (!$sourceID) $sourceID = $shareInfo['sourceID'];
$sourceInfo = Model('Source')->sourceInfo($sourceID);
$parent = Model('Source')->parentLevelArray($sourceInfo['parentLevel']);
array_push($parent,$sourceID);
if(!$sourceInfo || !in_array($sourceID,$parent) ){
return $this->errorMsg(LNG('explorer.share.notExist'));
}
// 自己的分享,不判断权限;协作中添加了自己或自己所在的部门;
if( $sourceInfo['targetType'] == SourceModel::TYPE_USER &&
$sourceInfo['targetID'] == USER_ID ){
return true;
}
return $this->checkAuthMethod($shareInfo['auth']['authValue'],$method);
}
//解析上述配置到action列表;统一转为小写;
private function actionParse(){
$actionArray = array();
foreach ($this->actionPathCheck as $authType => $modelActions) {
foreach ($modelActions as $controller => $stActions) {
if(!$stActions) continue;
$stActions = explode(',',trim($stActions,','));
foreach ($stActions as $action) {
$fullAction = strtolower($controller.'.'.$action);
if(!isset($actionArray[$fullAction])){
$actionArray[$fullAction] = array();
}
$actionArray[$fullAction][] = $authType;
}
}
}
// pr($actionArray,$this->actionPathCheck);exit;
return $actionArray;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/authUser.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 检测某人对某文档操作权限
*/
class explorerAuthUser extends Controller {
function __construct() {
parent::__construct();
}
/**
* 检测文档权限,是否支持$action动作
* path: 支持物理路径/io路径/source路径; (不支持其他路径)
* action: view,download,upload,edit,remove,share,comment,event,root
*/
public function can($path,$action,$userID){
$roleInfo = Action('user.authRole')->userRoleGet($userID);
if(!$roleInfo) return false;
$isRoot = $roleInfo['info']['administrator'] == 1;
if(!$isRoot && !Action('user.authRole')->canCheckRole($action)){return false;}
$parse = KodIO::parse($path);$ioType = $parse['type'];
// 物理路径 io路径拦截;只有管理员且开启了访问才能做相关操作;
if( $ioType == KodIO::KOD_IO || $ioType == false ){
$allowIO = $isRoot || ($roleInfo['allowAction']['admin.storage.edit'] == 1);
if($allowIO && $this->config["ADMIN_ALLOW_IO"]) return true;
return false;
}
if($isRoot && $this->config["ADMIN_ALLOW_SOURCE"]) return true;
$pathInfo = Model('Source')->pathInfo($parse['id']);
$targetType = $pathInfo['targetType'];
if(!$pathInfo || $pathInfo['isDelete'] == '1') return false;//不存在,不判断文档权限;
if( $targetType != 'user' && $targetType != 'group' ) return false;// 不是个人或部门文档
if( $targetType == 'user' && $pathInfo['targetID'] != $userID ) return false; //个人文档但不是自己的文档
//部门文档:权限拦截;会自动匹配权限;我在的部门会有对应权限
if($targetType == 'group'){
$selfAuth = $this->makeUserAuth($userID,$parse['id']);
if(!$selfAuth || !Model("Auth")->authCheckAction($selfAuth['authValue'],$action)) return false;
}
return true;
}
public function canShare($shareInfo){
if(!$shareInfo) return false;
// 兼容早期版本,该字段为空的情况;
if(!$shareInfo['sourcePath'] && $shareInfo['sourceID'] != '0'){
$shareInfo['sourcePath'] = KodIO::make($shareInfo['sourceID']);
}
if($shareInfo['isLink'] == '0' && $shareInfo['isShareTo'] == '0'){return false;}
if($shareInfo['userID'] == '0'){return true;} // 系统分享,允许访问;
// 系统分享;则不检测;
$isSystemSource = '/systemPath/systemSource/';
$pathDisplay = _get($shareInfo,'sourceInfo.pathDisplay');
$isSystem = _get($shareInfo,'sourceInfo.targetType') == 'system';
if(substr($pathDisplay,0,strlen($isSystemSource)) == $isSystemSource && $isSystem) return true;
return $this->can($shareInfo['sourcePath'],'share',$shareInfo['userID']);
}
public function makeUserAuth($userID,$sourceID){
$pathInfo = Model('Source')->pathInfo($sourceID);
$authList = Model("SourceAuth")->getSourceList(array($sourceID),false,$userID);
if( $authList && isset($authList[$sourceID])) return $authList[$sourceID];
return Action('explorer.listGroup')->pathGroupAuthMake($pathInfo['targetID'],$userID);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/autoPathParse.class.php'
<?php
// source 路径自动解析补全处理; {source:xx1}/aa/bb/c; ==> 转为{source:xx2}
class explorerAutoPathParse extends Controller {
function __construct() {
parent::__construct();
}
// 入口统一处理;
public function parseAuto(){
$theAction = strtolower(ACTION);
$checkArr = array(
'explorer.index.pathinfo' => array('path','[dataArr]'),
'explorer.index.pathrename' => array('path'),
'explorer.index.pathdelete' => array('[dataArr]'),
'explorer.index.pathcopy' => array('[dataArr]'),
'explorer.index.pathcute' => array('[dataArr]'),
'explorer.index.pathcopyto' => array('path','[dataArr]'),
'explorer.index.pathcuteto' => array('path','[dataArr]'),
'explorer.index.mkdir' => array('path'),
'explorer.index.mkfile' => array('path'),
'explorer.index.filesave' => array('path'),
'explorer.index.setmeta' => array('path'),
'explorer.index.setdesc' => array('path'),
'explorer.index.setauth' => array('path'),
'explorer.index.fileout' => array('path'),
'explorer.index.filedownload' => array('path'),
'explorer.index.zipdownload' => array('path'),
'explorer.index.filedownloadremove' => array('path'),
'explorer.index.fileoutby' => array('path'),
'explorer.index.unzip' => array('path','pathTo'),
'explorer.index.unziplist' => array('path'),
'explorer.index.pathlog' => array('path'),
'explorer.index.filethumb' => array('path'),
'explorer.list.path' => array('path'),
'explorer.list.listall' => array('path'),
'explorer.usershare.add' => array('path'),
'explorer.upload.fileupload' => array('path'),
'explorer.upload.serverdownload'=> array('path'),
'explorer.editor.fileget' => array('path'),
'explorer.editor.filesave' => array('path'),
);
if(!$checkArr[$theAction]){return;}
$allowNotMatchAction = array(
'explorer.index.mkdir' => 1,
'explorer.index.mkfile' => 1,
'explorer.index.unzip' => 1,
);
$allowNotMatch = isset($allowNotMatchAction[$theAction]) ? true : false;
foreach($checkArr[$theAction] as $key){
if(substr($key,0,1) == '['){
$this->parseArr(substr($key,1,-1),$allowNotMatch);
}else{
$this->parseKey($key,$allowNotMatch);
}
}
// pr($this->in,$_REQUEST);exit;
}
public function parseKey($key,$allowNotMatch=false){
if(!$this->in[$key]){return;}
$this->in[$key] = $this->parsePath($this->in[$key],$allowNotMatch);
}
public function parseArr($key,$allowNotMatch=false){
$data = json_decode($this->in[$key],true);
if(!is_array($data)){return;}
foreach($data as $k=>$v){
if(!is_array($v) || !isset($v['path'])){continue;}
$data[$k]['path'] = $this->parsePath($v['path'],$allowNotMatch);
}
$this->in[$key] = json_encode($data);
}
public function parsePath($path,$allowNotMatch=false){
if(!$path){return $path;}
if(substr($path,0,8) == '{search}'){
return $this->parseSourceSearch($path);
}
if(substr($path,0,8) != '{source:'){return $path;}
$path = KodIO::clear($path);
$info = preg_match("/^(\{source:(\d+)\})(\/?.*)$/",$path,$match);
if(!$match || !trim($match[3],'/')){return $path;}
$pathArr = explode('/',trim($match[3],'/'));
$sourceID = $match[2];
foreach($pathArr as $i=>$name){
$pathInfo = $this->parseSource($sourceID,$name);
if(!$pathInfo){ // 不存在时, 当前文档为文件时; 直接返回; 允许文件路径后续追加无效内容;
$itemInfo = Model("Source")->field("sourceID,name,isFolder")->where(array('sourceID'=>$sourceID,'isDelete'=>0))->find();
if($itemInfo && $itemInfo['isFolder'] == '0'){$pathInfo = $itemInfo;}
}
if($pathInfo && $pathInfo['isFolder'] == '0'){// 如果是文件则直接返回;忽略后续内容;
$sourceID = $pathInfo['sourceID'];break;
}
if($pathInfo){$sourceID = $pathInfo['sourceID'];continue;}
if(!$allowNotMatch){return show_json(LNG('common.pathNotExists'),false);}
return '{source:'.$sourceID.'}/'.implode('/',array_slice($pathArr,$i));
}
return '{source:'.$sourceID.'}/';
}
private function parseSourceSearch($path){
if(substr($path,0,8) != '{search}'){return $path;}
if(!strstr($path,'parentPath=')){return $path;}
$all = explode('@',ltrim(substr($path,8),'/'));
$result = array();
foreach ($all as $item) {
$keyv = explode('=',$item ? $item : '');
if(count($keyv) == 2 || $keyv[0] == 'parentPath'){
$value = trim(rawurldecode($keyv[1]));
$value = $this->parsePath($value);
$item = $keyv[0].'='.rawurlencode($value);
}
$result[] = $item;
}
return '{search}/'.implode('@',$result);
}
private function parseSource($sourceID,$name){
static $cache = array();
$cacheKey = $sourceID.'-'.$name;
if(!trim($name)){return $sourceID;}
if(array_key_exists($cacheKey,$cache)){
return $cache[$cacheKey];
}
$where = array('parentID'=>$sourceID,'name'=>$name,'isDelete'=>0);
$pathInfo = Model("Source")->field("sourceID,name,isFolder")->where($where)->find();
$cache[$cacheKey] = $pathInfo ? $pathInfo : 0;
return $cache[$cacheKey];
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/editor.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerEditor extends Controller{
function __construct() {
parent::__construct();
}
public function fileGet(){
$path = Input::get('path','require');
$this->fileGetHistoryCheck($path);
$this->fileGetZipContentCheck($path);
if(request_url_safe($path)){
$driver = new PathDriverUrl();
return $this->fileGetMake($path,$driver->info($path),$path);
}
$pathInfo = Action('explorer.index')->pathInfoItem($path);
Action('explorer.index')->updateLastOpen($path);
$this->fileGetMake($path,$pathInfo);
}
// 历史版本文件获取;
private function fileGetHistoryCheck($path){
if(!request_url_safe($path)) return;
$urlInfo = parse_url_query($path);
if(!isset($urlInfo['explorer/history/fileOut']) || !isset($urlInfo['path'])) return;
$this->in['path'] = rawurldecode($urlInfo['path']);
$this->in['id'] = $urlInfo['id'];
$info = IO::info($this->in['path']);
if(!$info) return;
$action = isset($info['sourceID']) ? 'explorer.history':'explorer.historyLocal';
$pathInfo = Action($action)->fileInfo();// 内部做权限检测;
if(!$pathInfo){return show_json(LNG('common.pathNotExists'),false);}
$this->fileGetMake($pathInfo['path'],$pathInfo,$path);exit;
}
private function contentPage($path,$size){
// if($size >= 1024*1024*20){show_json(LNG('explorer.editor.fileTooBig'),false);}
$PAGE_MIN = 1024 * 100;
$PAGE_MAX = $GLOBALS['config']['settings']['ioReadMax'];
$pageNum = _get($this->in,'pageNum',1024 * 500);
$pageNum = $pageNum <= $PAGE_MIN ? $PAGE_MIN : ($pageNum >= $PAGE_MAX ? $PAGE_MAX : $pageNum);
$pageNumOld = $pageNum;
if($pageNum >= $size){$pageNum = $size;}
$pageTotal = $pageNum > 0 ? ceil($size/$pageNum):0;
$page = _get($this->in,'page',1);
$page = $page <= 1 ? 1 : ($page >= $pageTotal ? $pageTotal : $page);
$from = 0;$length = $size;
if($size > $PAGE_MIN){
$from = ($page - 1) * $pageNum;
$length = $pageNum;
}
if(request_url_safe($path)){
$driver = new PathDriverUrl();
$content = $driver->fileSubstr($path,$from,$length);
}else{
$content = IO::fileSubstr($path,$from,$length);
}
if($content === false){
show_json(IO::getLastError(LNG('explorer.error')),false);
}
if($size == 0){$content = '';}
return array(
'content' => $content,
'pageInfo' => array(
'page' => $page,
'pageNum' => $pageNumOld,
'pageTotal' => $pageTotal,
'totalNum' => $size
)
);
}
// 压缩包内文件请求优化; 请求内部文件链接识别并处理成直接访问
private function fileGetZipContentCheck($path){
if(!request_url_safe($path)) return;
$urlInfo = parse_url_query($path);
if(!isset($urlInfo['index']) || !isset($urlInfo['path']) || !isset($urlInfo['accessToken'])) return;
if(!Action('user.index')->accessTokenCheck($urlInfo['accessToken'])){return;}
$zipFile = rawurldecode($urlInfo['path']);
$indexArr = @json_decode(rawurldecode($urlInfo['index']),true);
if(!$indexArr || !$zipFile){show_json(LNG('common.pathNotExists'),false);}
$isShareFile = isset($urlInfo['explorer/share/unzipList']);
$isViewFile = isset($urlInfo['explorer/index/unzipList']);
// 权限判断;
if($isShareFile){
$shareFileInfo = Action("explorer.share")->sharePathInfo($zipFile);
if(!$shareFileInfo){show_json(LNG('explorer.noPermissionAction'),false);}
$zipFile = $shareFileInfo['path'];
}else if($isViewFile){
if(!Action('explorer.auth')->canRead($zipFile)){
show_json(LNG('explorer.noPermissionAction'),false);
}
}else{return;}
// 解压处理;
$filePart = IOArchive::unzipPart($zipFile,$indexArr);
if(!$filePart || !IO::exist($filePart['file'])){
show_json(LNG('common.pathNotExists'),false);
}
$this->fileGetMake($filePart['file'],IO::info($filePart['file']),$path);exit;
}
public function fileGetMake($path,$pathInfo,$pathUrl = false){
// pr($path,$pathInfo,$pathUrl);exit;
if($pathUrl){ //url类文件信息处理; 只读, pathUrl,编辑器刷新支持;
$urlInfo = parse_url_query($pathUrl);
$showPath = trim(rawurldecode($urlInfo['name']),'/');
if(isset($urlInfo['index']) && $urlInfo['index']){ // 压缩包内部文件;
$indexArr = json_decode(rawurldecode($urlInfo['index']),true);
if(is_array($indexArr)){$showPath = $indexArr[count($indexArr) - 1]['name'];}
}
$pathInfo['path'] = '';$pathInfo['pathUrl'] = $pathUrl;
$pathInfo['name'] = get_path_this($showPath);
$pathInfo['ext'] = get_path_ext($pathInfo['name']);
$pathInfo['pathDisplay'] = "[".$showPath."]";
$pathInfo['isWriteable'] = false;
}
if(!$pathInfo || $pathInfo['type'] == 'folder'){
return show_json(LNG('common.pathNotExists'),false);
}
Hook::trigger('explorer.fileGet', $path);
$contentInfo = $this->contentPage($path,$pathInfo['size']);
$content = $contentInfo['content'];
if(isset($this->in['charset']) && $this->in['charset']){
$charset = strtolower($this->in['charset']);
}else{
$charset = strtolower(get_charset($content));
}
//ISO-8859-1 // 0x00 ~ 0xff;不做转换 1字节全; byte类型; 避免编码转换导致内容变化的情况: \xC3\x86 => \xC6;
$isBindary = strstr($content,"\x00") ? true:false;//pr($isBindary,$content);exit;
if($isBindary){$this->in['base64'] = 1;}
if($isBindary && !isset($this->in['charset'])){$charset = 'iso-8859-1';}
if(!$isBindary && $charset !='' && $charset !='utf-8' && function_exists("mb_convert_encoding")){
$content = @mb_convert_encoding($content,'utf-8',$charset);
}
$data = array_merge($pathInfo,array(
'charset' => $charset,
'base64' => $this->in['base64'] == '1' ?'1':'0',// 部分防火墙编辑文件误判问题处理
'pageInfo' => $contentInfo['pageInfo'],
'content' => $content,
));
// 避免截取后乱码情况; 去掉不完整的字符(一个汉字3字节,最后剩余1,2字节都会导致乱码)
if(!$isBindary && is_text_file($pathInfo['ext']) && $data['pageInfo']['pageTotal'] > 1){
$data['content'] = utf8Repair($data['content'],chr(1));
}
if($data['base64']=='1'){
$data['content'] = strrev(base64_encode($data['content']));
}
show_json($data);
}
public function fileSave(){
$data = Input::getArray(array(
'path' => array('check'=>'require'),
'content' => array('default'=>''),
'base64' => array('default'=>''),
'charset' => array('default'=>''),
'charsetSave' => array('default'=>''),
));
$pathInfo = IO::info($data['path']);
if(!$pathInfo) show_json(LNG('common.pathNotExists'),false);
//支持二进制文件读写操作(base64方式)
$content = $data['content'];
if($data['base64'] == '1'){
$content = base64_decode(strrev($content));//避免防火墙拦截部分关键字内容
}
$charset = strtolower($data['charset']);
$charsetSave = strtolower($data['charsetSave']);
$charset = $charsetSave ? $charsetSave : $charset;
if ( $charset !='' &&
$charset != 'utf-8' &&
$charset != 'ascii' &&
function_exists("mb_convert_encoding")
) {
$content = @mb_convert_encoding($content,$charset,'utf-8');
}
$result = IO::setContent($data['path'],$content);
$msg = $result ? LNG("explorer.saveSuccess") : IO::getLastError(LNG('explorer.saveError'));
$pathInfo = Action('explorer.index')->pathInfoItem($data['path']);
show_json($msg,!!$result,$pathInfo);
}
/*
* 保存编辑器配置信息
*/
public function setConfig(){
$optionKey = array_keys($this->config['editorDefault']);
$data = Input::getArray(array(
"key" => array("check"=>"in","param"=>$optionKey),
"value" => array("check"=>"require"),
));
Model('UserOption')->set($data['key'],$data['value'],'editor');
show_json(LNG('explorer.settingSuccess'));
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/fav.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerFav extends Controller{
private $model;
function __construct(){
parent::__construct();
$this->model = Model('UserFav');
}
/**
* 获取收藏夹json
*/
public function get() {
$pageNum = $GLOBALS['in']['pageNum'];$GLOBALS['in']['pageNum'] = 2000;//分页处理;
$list = $this->model->listView();
// 收藏协作分享内容;
foreach($list as $key => $item) {
$pathParse = KodIO::parse($item['path']);
if($pathParse['type'] == KodIO::KOD_SHARE_ITEM){
$infoItem = IO::info($item['path']);
$infoItem = is_array($infoItem) ? $infoItem :array();
$list[$key] = array_merge($item,$infoItem);
}
}
$GLOBALS['in']['pageNum'] = $pageNum ? $pageNum:null;
return $this->_checkExists($list);
}
private function _checkExists($list){
foreach ($list as &$item) {
if(!isset($item['sourceInfo'])){
$item['sourceInfo'] = array();
}
$item['sourceInfo']['isFav'] = 1;
if(!$item['sourceInfo']['favName']){
$item['sourceInfo']['favName'] = $item['name'];
}
if(!$item['sourceInfo']['favID']){
$item['sourceInfo']['favID'] = $item['id'];
}
unset($item['id']);
if( $item['type'] == 'source' && $item['sourceID']){
$item['type'] = $item['isFolder'] == '1' ? 'folder':'file';
$item['path'] = KodIO::make($item['path']);
continue;
}
if( $item['type'] == 'source' ){
// 文件不存在处理;
$item['type'] = 'folder';
$item['exists'] = false;
$item['path'] = KodIO::make($item['path']);
}else{
$info = Action('explorer.list')->pathCurrent($item['path'],false);
if($item['type'] == 'file'){$info['type'] = 'file';}
unset($info['name']);
$item = array_merge($item,$info);
if($item['type'] == 'file'){$item['ext'] = get_path_ext($item['name']);}
}
};unset($item);
return $list;
}
public function favAppendItem(&$item){
static $listPathMap = false;
if($listPathMap === false){
$listPathMap = $this->model->listData();
$listPathMap = array_to_keyvalue($listPathMap,'path');
}
if(!isset($item['sourceInfo'])){$item['sourceInfo'] = array();}
$path = $item['path'];$path1 = rtrim($item['path'],'/');$path2 = rtrim($item['path'],'/').'/';
$findItem = isset($listPathMap[$path]) ? $listPathMap[$path]:false;
$findItem = (!$findItem && isset($listPathMap[$path1])) ? $listPathMap[$path1]:$findItem;
$findItem = (!$findItem && isset($listPathMap[$path2])) ? $listPathMap[$path2]:$findItem;
if($findItem){
$item['sourceInfo']['isFav'] = 1;
$item['sourceInfo']['favName'] = $findItem['name'];
$item['sourceInfo']['favID'] = $findItem['id'];
}
if($item['type'] == 'file' && !$item['ext']){
$item['ext'] = get_path_ext($item['name']);
}
return $item;
}
/**
* 添加
*/
public function add(){
$data = Input::getArray(array(
"path" => array("check"=>"require"),
"name" => array("check"=>"require"),
"type" => array("check"=>"require","default"=>'folder'),
));
$list = $this->model->listData();
$list = is_array($list) ? $list : array();
if( count($list) > $GLOBALS['config']['systemOption']['favNumberMax'] ){
show_json(LNG("common.numberLimit"),false);
}
$pathInfo = KodIO::parse($data['path']);
if($pathInfo['type'] == KodIO::KOD_USER_FAV){
//show_json(LNG("explorer.pathNotSupport"),false);
}
if($pathInfo['type'] == KodIO::KOD_SOURCE){
$data['type'] = 'source';
$data['path'] = $pathInfo['id'];
Action('explorer.listSafe')->authCheckAllow($data['path']);
}
$res = $this->model->addFav($data['path'],$data['name'],$data['type']);
$msg = !!$res ? LNG('explorer.addFavSuccess') : LNG('explorer.pathHasFaved');
show_json($msg,!!$res);
}
/**
* 重命名
*/
public function rename() {
$data = Input::getArray(array(
"name" => array("check"=>"require"),
"newName" => array("check"=>"require"),
"path" => array("check"=>"require","default"=>false),
));
$res = $this->model->rename($data['name'],$data['newName']);
$msg = !!$res ? LNG('explorer.success') : LNG('explorer.repeatError');
$info = $res && $data['path'] ? $data['path']:false;
show_json($msg,!!$res,$data['path']);
}
/**
* 置顶
*/
public function moveTop() {
$name = Input::get('name','require');
$res = $this->model->moveTop($name);
$msg = !!$res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res);
}
/**
* 置底
*/
public function moveBottom() {
$name = Input::get('name','require');
$res = $this->model->moveBottom($name);
$msg = !!$res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res);
}
/**
* 重置排序,根据id的顺序重排;
*/
public function resetSort() {
$idList = Input::get('favList',"require");
$idArray = explode(',',$idList);
if(!$idArray) {
show_json(LNG('explorer.error'),false);
}
$res = $this->model->resetSort($idArray);
$msg = $res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res);
}
/**
* 删除
*/
public function del() {
$name = Input::get('name','require');
$res = $this->model->removeByName($name);
$msg = !!$res ? LNG('explorer.delFavSuccess') : LNG('explorer.error');
show_json($msg,!!$res);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/fileView.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerFileView extends Controller{
public function __construct(){
parent::__construct();
$this->model = Model("Source");
}
public function index(){
$file = $this->in['path'];
$fileInfo = IO::info($file);
$app = $this->getAppUser($fileInfo['ext']);
$fileUri = rawurlencode($file);
if(!$app){
return header('Location: '.APP_HOST.'#fileView&path='.$fileUri);
}
$object = Action($app.'Plugin');
$existMethod = method_exists($object,'index');
if(!$existMethod){
return header('Location: '.APP_HOST.'#fileView&path='.$fileUri);
}
$link = urlApi('plugin/'.$app,'path='.$fileUri);
$link .= '&ext='.rawurlencode($fileInfo['ext']).'&name='.rawurlencode($fileInfo['name']);
header('Location: '.$link);
}
// 根据当前用户打开方式;
private function getAppUser($ext){
$list = $this->getAppSupport($ext,true);
if(!$list) return false;
$listName = array_to_keyvalue($list,'name');
$defaultSet = Model('UserOption')->get('kodAppDefault');
$defaultSet = json_decode(Model('UserOption')->get('kodAppDefault'),true);
$app = $list[0]['name'];
if( isset($defaultSet[$ext]) &&
isset($listName[$defaultSet[$ext]]) ){
$app = $listName[$defaultSet[$ext]]['name'];
}
return $app;
}
// 打开方式获取并排序;
private function getAppSupport($ext,$checkUserAuth = true){
$modelPlugin = Model("Plugin");
$list = $modelPlugin->loadList();
$listAllow = array();
foreach ($list as $app => $item) {
if( !isset($item['config']['fileExt']) ) continue;
$extArr = explode(',',$item['config']['fileExt']);
if( !in_array($ext,$extArr) ) continue;
if( $modelPlugin->appAllow($app,$item,$checkUserAuth) ){
$item['fileOpenSort'] = intval($item['config']['fileSort']);
$listAllow[] = $item;
}
}
$listAllow = array_sort_by($listAllow,'fileOpenSort',true);
return $listAllow;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/history.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerHistory extends Controller{
private $model;
function __construct(){
parent::__construct();
$this->model = Model('SourceHistory');
$this->checkAuth();
}
private function checkAuth(){
$path = Input::get('path','require');
$info = IO::info($path);
if( !isset($info['sourceID']) ){ // 物理目录,io路径代理请求;
Action('explorer.historyLocal')->delegate();exit;
}
Action('explorer.auth')->canWrite($path);
$this->sourceID = $info['sourceID'];
}
private function checkItem(){
$id = Input::get('id','require');
$where = array('sourceID' =>$this->sourceID,'id'=> $id);
$itemInfo = $this->model->where($where)->find();
if(!$itemInfo){ // 没有匹配到该文档的某条历史记录;
show_json(LNG('explorer.dataError'),false);
}
return $id;
}
/**
* 获取历史记录列表;
*/
public function get() {
$result = $this->model->listData($this->sourceID);
$result['current'] = IO::info($this->in['path']);
show_json($result);
}
/**
* 删除某个文件的某个版本;
*/
public function remove() {
$id = $this->checkItem();
$res = $this->model->removeItem($id);
$msg = !!$res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res);
}
/**
* 删除某个文件的所有版本;
*/
public function clear() {
$res = $this->model->removeBySource($this->sourceID);
$msg = !!$res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res);
}
//设置某个版本为最新版;
public function rollback() {
$id = $this->checkItem();
$fileInfo = $this->model->fileInfo($id);
Model("Source")->checkLock($this->sourceID,$fileInfo['fileID']);
$res = $this->model->rollbackToItem($this->sourceID,$id);
$msg = !!$res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res);
}
public function setDetail(){
$maxLength = $GLOBALS['config']['systemOption']['historyDescLengthMax'];
$msg = LNG('common.lengthLimit').'('.LNG('explorer.noMoreThan').$maxLength.')';
$data = Input::getArray(array(
'detail'=> array('check'=>'length','param'=>array(0,$maxLength),'msg'=>$msg),
));
$id = $this->checkItem();
$res = $this->model->setDetail($id,$data['detail']);
$msg = !!$res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res);
}
public function fileOut(){
$fileInfo = $this->fileInfo();
$isDownload = isset($this->in['download']) && $this->in['download'] == 1;
Hook::trigger('explorer.fileOut', $fileInfo['path']);
if(isset($this->in['type']) && $this->in['type'] == 'image'){
return IO::fileOutImage($fileInfo['path'],$this->in['width']);
}
$name = !empty($this->in['name']) ? $this->in['name'] : $fileInfo['name'];
IO::fileOut($fileInfo['path'],$isDownload,$name);
}
public function fileInfo(){
$id = $this->checkItem();
return $this->model->fileInfo($id);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/historyLocal.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 本地文件,io文件历史记录
*
*
* 历史版本生成
* 操作触发检测: 文件编辑保存;上传覆盖;粘贴覆盖;(排除历史版本回退) IO::setContent
* 目录变更更新: 重命名,上层文件夹重命名;移动,上层文件夹移动;
* 删除处理: 文件删除,上层文件夹删除;
* 历史版本管理: 列表,打开,下载;回退,删除,清空; diff对比
*/
class explorerHistoryLocal extends Controller{
function __construct(){
parent::__construct();
$this->checkAuth();
}
public function checkAuth(){
$path = Input::get('path','require');
Action('explorer.auth')->canWrite($path);
$this->path = $this->parsePath($path);
if(!$this->path){
show_json(LNG('explorer.dataError'),false);
}
}
public function delegate(){
$action = ACT;
$this->$action();
}
// 目录检测;
private function parsePath($path){
if(!$path) return false;
$pathParse = KodIO::parse($path);
$driverType = $pathParse['type'];
$allow = !$driverType || $driverType == KodIO::KOD_IO || $driverType == KodIO::KOD_SHARE_ITEM;
if(!$allow || !$pathParse['isTruePath']) return false;
if($driverType == KodIO::KOD_SHARE_ITEM){
$driver = IO::init($path);
if($driver->pathParse['truePath']){
return $this->parsePath($driver->pathParse['truePath']);
}
return false;
}
return $path;
}
public function get(){
$history = IOHistory::listData($this->path);
if(!$history){show_json(LNG('explorer.dataError'),false);}
$result = array_page_split($history['list']);
if(Model('SystemOption')->get('versionType') == 'A'){
$result['list'] = array_slice($history['list'],0,5);
$result['pageInfo']['totalNum'] = count($result['list']);
$result['pageInfo']['pageTotal'] = 1;
$result['pageInfo']['page'] = 1;
}
$userList = array();
foreach ($result['list'] as $key=>$item){
$userKey = 'user-'.$item['createUser'];
if(!$userList[$userKey]){
$userList[$userKey] = Model("User")->getInfoSimpleOuter($item['createUser']);
}
$result['list'][$key]['createUser'] = $userList[$userKey];
}
$result['current'] = IO::info($this->in['path']);
show_json($result);
}
public function remove(){
$res = IOHistory::remove($this->path,$this->in['id']);
$msg = $res ? LNG('explorer.success') : IO::getLastError(LNG('explorer.error'));
show_json($msg,!!$res);
}
public function clear(){
$res = IOHistory::clear($this->path);
$msg = $res ? LNG('explorer.success') : IO::getLastError(LNG('explorer.error'));
show_json($msg,!!$res);
}
// 回滚到最新; 将某个版本设置为当前版本;
public function rollback() {
$res = IOHistory::rollback($this->path,$this->in['id']);
$msg = $res ? LNG('explorer.success') : IO::getLastError(LNG('explorer.error'));
show_json($msg,!!$res);
}
public function setDetail(){
$maxLength = $GLOBALS['config']['systemOption']['historyDescLengthMax'];
$msg = LNG('common.lengthLimit').'('.LNG('explorer.noMoreThan').$maxLength.')';
$data = Input::getArray(array(
'detail'=> array('check'=>'length','param'=>array(0,$maxLength),'msg'=>$msg),
));
$res = IOHistory::setDetail($this->path,$this->in['id'],$data['detail']);
$msg = $res ? LNG('explorer.success') : LNG('explorer.dataError');
show_json($msg,!!$res);
}
public function fileOut(){
IOHistory::fileOut($this->path,$this->in['id']);
}
public function fileInfo(){
return IOHistory::fileInfo($this->path,$this->in['id']);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/index.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerIndex extends Controller{
private $model;
public function __construct(){
parent::__construct();
$this->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']){
$metaArr = array();
foreach ($meta as $key => $value) {
if( !$this->metaKeyCheck($key,$value,$info) ){
show_json("key error!",false);
}
$metaArr[$key] = $value === '' ? null:$value; //为空则删除;
$this->model->metaSet($info['sourceID'],$key,$value);
}
// 设置文件夹密码,自动设置密码用户为当前用户;
if(isset($metaArr['folderPassword'])){
$metaArr['folderPasswordUser'] = $metaArr['folderPassword'] ? USER_ID:null;
}
$this->model->metaSet($info['sourceID'],$metaArr);
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', // 编辑锁定时间
'folderPassword', // 文件夹密码
'folderPasswordDesc', // 文件夹密码描述
'folderPasswordTimeTo', // 文件夹密码过期时间,为空则代表不限制时间;
));
}
$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); // 缩略图尺寸
// 同时删除缩略图目录下fileID对应的所有记录(即包括其他文件生成的相同缩略图)
$coverList = array();
foreach ($thumbList as $width){
$coverName = "cover_{$fileHash}_{$width}.png";
$coverList[] = $coverName;
// $coverName = "cover_{$fileHash}_{$width}.jpg"; // 缩略图格式改为jpg,暂不处理
// $coverList[] = $coverName;
}
$parentID = KodIO::sourceID($fileThumbInfo['path']);
$where = array(
's.parentID' => $parentID,
's.name' => array('in',$coverList),
's.isDelete' => 0
);
$list = Model('Source')->alias('s')->field('s2.sourceID,s2.name')
->join("INNER JOIN `io_source` s2 ON s.parentID = s2.parentID AND s.fileID = s2.fileID")
->where($where)->select();
if (!$list) $list = array();
foreach ($list as $item){
$sourceID = $item['sourceID'];
Cache::remove($item['name']);
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','getAllParent','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'] == 'getAllParent'){
//该文件夹所有有权限的用户或部门;向上回溯全部查询; 有权限的用户列表(用户/部门,最终合并计算后的权限;权限来源)
$result = Model('SourceAuth')->getAllParent($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($content){
if(_get($this->in,'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 = IO::getLastError(LNG('explorer.error'));}
if($errorList){$msg .= "(".count($errorList)." error)";}
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);
$shareInfo = Action('explorer.share')->shareInfoLast();
if(!$info || !$shareInfo){
show_json($GLOBALS['explorer.sharePathInfo.error'], false);
}
if($shareInfo['options'] && $shareInfo['options']['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->update(0,true);//立即保存,部分解压方式不触发任务更新,导致进度获取失败
$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']);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/lightApp.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerLightApp extends Controller{
private $model;
function __construct() {
$this->model = Model('SystemLightApp');
parent::__construct();
}
/**
* 获取列表
* 通过分类获取;默认为all
*/
public function get() {
$group = Input::get('group','require','all');
$list = $this->model->listData(false,'id');
$result = array();
foreach ($list as $item) {
if($item['group'] == $group || $group == 'all'){
$result[] = $item;
}
}
show_json($result);
}
/**
* 添加
*/
public function add() {
$res = $this->model->add($this->input());
$msg = !!$res ? LNG('explorer.success') : LNG('explorer.repeatError');
show_json($msg,!!$res);
}
/**
* 编辑
*/
public function edit() {
$name = $this->in['beforeName'];
$res = $this->model->update($name,$this->input());
$msg = !!$res ? LNG('explorer.success') : LNG('explorer.repeatError');
show_json($msg,!!$res);
}
/**
* 删除
*/
public function del() {
$name = rawurldecode($this->in['name']);
$res = $this->model->remove($name);
$msg = !!$res ? LNG('explorer.success') : LNG('common.notExists');
show_json($msg,!!$res);
}
public function getUrlContent(){
$url = $this->in['url'];
$header = url_header($url);
if(!$header){show_json(array());}
$contentType = $header['all']['content-type'];
if(is_array($contentType)){$contentType = $contentType[count($contentType) - 1];}
if(strstr($contentType,'text/html')){
$content = curl_get_contents($url,30);
$charset = get_charset($content);
if($charset !='' && $charset !='utf-8' && function_exists("mb_convert_encoding")){
$content = @mb_convert_encoding($content,'utf-8',$charset);
}
show_json(array('html'=>$content,'header'=>$header));
}
// 图片等处理;
if(strstr($contentType,'image')){
$content = curl_get_contents($url,30);
show_json(array("content"=>base64_encode($content),'isBase64'=>true,'header'=>$header),true);
}
show_json(array('header'=>$header));
}
private function input(){
$arr = json_decode($this->in['data'],true);
if(!is_array($arr)){
show_json(LNG('explorer.error'),false);
}
return $arr;
}
/**
* 轻应用列表初始化
*/
public function initApp(){
$this->clearOldApps();
$str = file_get_contents(BASIC_PATH.'data/system/apps.php');
$data = json_decode(substr($str, strlen('<?php exit;?>')),true);
$data = is_array($data) ? $data : array();
$data = array_reverse($data);
foreach ($data as $app) {
$type = $app['type'] == 'app' ? 'js' : $app['type'];
$item = array(
'name' => $app['name'],
'group' => $app['group'],
'desc' => $app['desc'],
'content' => array(
'type' => $type,
'value' => $app['content'],
'icon' => $app['icon'],
'options' => array(
"width" => $app['width'],
"height" => $app['height'],
"simple" => $app['simple'],
"resize" => $app['resize']
),
)
);
if(isset($app['openType'])){
$item['content']['options']['openType'] = $app['openType'];
}
if( $this->model->findByName($item['name']) ){
$this->model->update($item['name'],$item);
}else{
$this->model->add($item);
}
}
}
private function clearOldApps(){
// $this->model->clear();
$clearOld = array(
"豆瓣电台","365日历",
'Kingdom Rush','Vector Magic','中国象棋','天气',"iqiyi影视",
'计算器','音悦台','黑8对决','Web PhotoShop','一起写office',
"微信","百度DOC",'百度随心听',"腾讯canvas","pptv直播","搜狐影视",
);
foreach($clearOld as $app){
$this->model->remove($app);
}
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/list.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 文件列表通用入口获取
* 基本数据: current/folderList/fileList/pageInfo;
*
* 其他参数
* listTypeSet // 指定列表模式; icon,list,split
* listTypePhoto // 强制显示图片模式
* disableSort // 是否禁用排序; 0,1
* pageSizeArray // 自定义分页数量选择;
* folderTips // 目录警告提示信息;
* groupShow // 分组依据;
*/
class explorerList extends Controller{
private $model;
public function __construct(){
parent::__construct();
$this->model = Model("Source");
}
public function path($thePath = false){
$path = $thePath ? $thePath : $this->in['path'];
$path = $path != '/' ? rtrim($path,'/') : '/';//路径保持统一;
$path = $path == '{io:systemRecycle}' ? IO_PATH_SYSTEM_RECYCLE:$path;
$path = $this->checkDesktop($path);
$pathParse= KodIO::parse($path);
$id = $pathParse['id'];
$current = $this->pathCurrent($path);
$this->checkExist($current,$path);
switch($pathParse['type']){
case KodIO::KOD_USER_FAV: $data = Action('explorer.fav')->get();break;
case KodIO::KOD_USER_FILE_TAG: $data = Action('explorer.tag')->listSource($id);break;
case KodIO::KOD_USER_RECYCLE: $data = $this->model->listUserRecycle();break;
case KodIO::KOD_USER_FILE_TYPE: $data = Action('explorer.listFileType')->get($id,$pathParse);break;
case KodIO::KOD_USER_RECENT: $data = Action('explorer.listRecent')->listData();break;
case KodIO::KOD_GROUP_ROOT_SELF: $data = Action('explorer.listGroup')->groupSelf($pathParse);break;
case KodIO::KOD_USER_SHARE: $data = Action('explorer.userShare')->myShare('to');break;
case KodIO::KOD_USER_SHARE_LINK: $data = Action('explorer.userShare')->myShare('link');break;
case KodIO::KOD_USER_SHARE_TO_ME: $data = Action('explorer.userShare')->shareToMe($id);break;
case KodIO::KOD_SHARE_ITEM: $data = Action('explorer.userShare')->sharePathList($pathParse);break;
case KodIO::KOD_SEARCH: $data = Action('explorer.listSearch')->listSearch($pathParse);break;
case KodIO::KOD_BLOCK: $data = Action('explorer.listBlock')->blockChildren($id);break;
case KodIO::KOD_SHARE_LINK:
case KodIO::KOD_SOURCE:
case KodIO::KOD_IO:
default:$data = IO::listPath($path);break;
}
if($data === false){ // 获取失败情况处理;
if($thePath){return false;}
return show_json(IO::getLastError(LNG('explorer.error')),false);
}
$this->parseData($data,$path,$pathParse,$current);
Action('explorer.listView')->listDataSet($data);
if($thePath) return $data;
show_json($data);
}
public function parseData(&$data,$path,$pathParse){
$this->parseAuth($data,$path,$pathParse);
$this->pageParse($data);
$this->parseDataHidden($data,$pathParse);
//回收站追加物理/io回收站;
Action('explorer.recycleDriver')->appendList($data,$pathParse);
Action('explorer.listGroup')->appendChildren($data);
Action('explorer.listSafe')->appendSafe($data);
Action('explorer.listPassword')->appendSafe($data);
$this->pathListParse($data);// 1000 => 50ms; all-image=200ms;
$this->pageReset($data);
$this->addHistoryCount($data,$pathParse);
}
// 拉取所有(用于文件夹同步,对比等情况)
// IO::listAll($this->in['path']);// path:默认为真实路径;包含sourceInfo时sourceInfo.path为真实路径;
public function listAll(){
$page = isset($this->in['page']) ? intval($this->in['page']):1;
$pageNum = isset($this->in['pageNum']) ? intval($this->in['pageNum']):2000;
$page = $page <= 1 ? 1:$page;$pageNum = $pageNum <= 1000 ? 1000:$pageNum;
$list = IO::listAllSimple($this->in['path'],0);// path:包含上层文件夹名的路径;filePath:真实路径;
$data = array_page_split($list,$page,$pageNum);
show_json($data);
}
// 桌面文件夹自动检测;不存在处理;
private function checkDesktop($path){
if(!defined('MY_DESKTOP')) return $path;
if(trim($path,'/') !== trim(MY_DESKTOP,'/')) return $path;
if(IO::info($path)) return MY_DESKTOP;//存在则不处理;
$desktopName = LNG('explorer.toolbar.desktop');
$model = Model("Source");
$find = IO::fileNameExist(MY_HOME,$desktopName);
$rootID = KodIO::sourceID(MY_HOME);
if(!$find){
$find = $model->mkdir($rootID,$desktopName);
}
$model->metaSet($find,'desktop','1');
$model->metaSet($rootID,'desktopSource',$find);
Model('User')->cacheFunctionClear('getInfo',USER_ID);
return KodIO::make($find);
}
public function pageParse(&$data){
if(isset($data['pageInfo'])) return;
$in = $this->in;
$pageNumMax = 50000;
$pageNum = isset($in['pageNum']) ? $in['pageNum'] : $pageNumMax;
if($pageNum === -1){ // 不限分页情况; webdav列表处理;
unset($in['pageNum']);
$pageNumMax = 1000000;
$pageNum = $pageNumMax;
}
$fileCount = count($data['fileList']);
$folderCount= count($data['folderList']);
$totalNum = $fileCount + $folderCount;
$pageNum = intval($pageNum);
$pageNum = $pageNum <= 5 ? 5 : ($pageNum >= $pageNumMax ? $pageNumMax : $pageNum);
$pageTotal = ceil( $totalNum / $pageNum);
$page = intval( isset($in['page'])?$in['page']:1);
$page = $page <= 1 ? 1 : ($page >= $pageTotal ? $pageTotal : $page);
$data['pageInfo'] = array(
'totalNum' => $totalNum,
'pageNum' => $pageNum,
'page' => $page,
'pageTotal' => $pageTotal,
);
if($pageTotal <= 1) return;
$sort = $this->_parseOrder();
$isDesc = $sort['desc'] == 'desc';
$data['fileList'] = KodSort::arraySort($data['fileList'],$sort['key'],$isDesc,'name');
$data['folderList'] = KodSort::arraySort($data['folderList'],$sort['key'],$isDesc,'name');
$start = ($page-1) * $pageNum;
$end = $start + $pageNum;
if( $end <= $folderCount){ // 文件夹范围内;
$data['folderList'] = array_slice($data['folderList'],$start,$pageNum);
$data['fileList'] = array();
}else if($start >= $folderCount){ // 文件范围内;
$data['folderList'] = array();
$data['fileList'] = array_slice($data['fileList'],$start-$folderCount,$pageNum);
}else{ // 各自占一部分;
$folderNeed = $folderCount - $start;
$data['folderList'] = array_slice($data['folderList'],$start,$folderNeed);
$data['fileList'] = array_slice($data['fileList'],0,$pageNum-($folderNeed) );
}
}
private function pageReset(&$data){
// 合并额外current数据;
if(is_array($data['currentFieldAdd'])){
$data['current'] = is_array($data['current']) ? $data['current'] : array();
$data['current'] = array_merge($data['current'],$data['currentFieldAdd']);
unset($data['currentFieldAdd']);
}
if(!isset($data['pageInfo'])) return;
$group = isset($data['groupList']) ? count($data['groupList']) : 0;
$total = count($data['fileList']) + count($data['folderList']) + $group;
$pageInfo = $data['pageInfo'];
if( $pageInfo['page'] == 1 && $pageInfo['pageTotal'] == 1){
$data['pageInfo']['totalNum'] = $total;
}
// 某一页因为权限全部过滤掉内容, 则加大每页获取条数;
if( $total == 0 && $pageInfo['totalNum'] != 0 && $pageInfo['pageTotal'] > 1 ){
$this->in['pageNum'] = $pageInfo['pageNum'] * 2;
if($this->in['pageNum'] < 500){
$this->in['pageNum'] = 500;
}
$newData = $this->path($this->in['path']);
show_json($newData);
}
}
// 文件历史版本数量追加;
private function addHistoryCount(&$data,$pathParse){
if($pathParse['type'] == KodIO::KOD_SHARE_LINK) return;
$sourceArr = array();$pathArr = array();
foreach ($data['fileList'] as $file){
if($file['sourceID']){
// 修改时间小于等于创建时间时无历史版本; 忽略判断, 上传文件保留最后修改时间;
// if($file['modifyTime'] <= $file['createTime']) continue;
$sourceArr[] = $file['sourceID'];
}
if(!$file['sourceID'] && $file['isWriteable']){$pathArr[] = $file['path'];}
}
$countSource = $sourceArr ? Model("SourceHistory")->historyCount($sourceArr):array();
$countLocal = $pathArr ? IOHistory::historyCount($pathArr):array();
// if(!$countSource && !$countLocal) return;
foreach ($data['fileList'] as $key=>$file){
$data['fileList'][$key]['historyCount'] = 0; //默认设置为0
if($file['sourceID'] && $countSource[$file['sourceID']]){
$data['fileList'][$key]['historyCount'] = intval($countSource[$file['sourceID']]);
}
if($countLocal[$file['path']]){
$data['fileList'][$key]['historyCount'] = intval($countLocal[$file['path']]);
}
}
}
public function fileInfoAddHistory($pathInfo){
if(!$pathInfo || $pathInfo['type'] != 'file') return;
$pathParse = KodIO::parse($pathInfo['path']);
$data = array('fileList'=>array($pathInfo));
$this->addHistoryCount($data,$pathParse);
return $data['fileList'][0];
}
private function _parseOrder(){
$defaultField = Model('UserOption')->get('listSortField');
$defaultSort = Model('UserOption')->get('listSortOrder');
$sortTypeArr = array('up'=>'asc','down'=>'desc');
$sortFieldArr = array(
'name' => 'name',
'size' => 'size',
'type' => 'ext',
'ext' => 'fileType',
'createTime' => 'createTime',
'modifyTime' => 'modifyTime'
);
$sortField = Input::get("sortField",'in',$defaultField,array_keys($sortFieldArr));
$sortType = Input::get("sortType", 'in',$defaultSort,array_keys($sortTypeArr));
if( !in_array($sortField,array_keys($sortFieldArr)) ){
$sortField = 'name';
}
if( !in_array($sortType,array_keys($sortTypeArr)) ){
$sortField = 'up';
}
return array('key'=>$sortFieldArr[$sortField],'desc'=>$sortTypeArr[$sortType]);
}
/**
* 检查目录是否存在;
*/
private function checkExist($current,$path){
if(trim($path,'/') == '{source:0}') return;
if(!$current || $current['exists'] === false){
show_json(LNG('common.pathNotExists'),false);
}
$fromDav = _get($GLOBALS,'requestFrom') == 'webdav';
if(isset($current['isDelete']) && $current['isDelete'] == '1' && !$fromDav){
show_json(LNG("explorer.pathInRecycle"),false);
}
}
public function pathCurrent($path,$loadInfo = true){
$pathParse = KodIO::parse($path);
try{// 收藏或访问的io路径不存在情况报错优化;
$driver = IO::init($path);
}catch(Exception $e){
$current = array('type'=>'folder','path'=>$path,'exists'=>false);
return $current;
}
if($pathParse['isTruePath']){
$current = array('type'=>'folder','path'=>$path);
if(!$driver) {$current['exists'] = false;}
if($driver && $loadInfo){
$current = IO::info($path);
$current = Model('SourceAuth')->authOwnerApply($current);
}
if($driver && !$loadInfo && $driver->getType() == 'local'){
$currentInfo = IO::info($path);
if($currentInfo){$current=$currentInfo;}
if(!$currentInfo){$current['exists'] = false;}
}
return $current;
}
$listBlock = Action('explorer.listBlock');
$current = $listBlock->ioInfo($pathParse['type']);
if($pathParse['type'] == KodIO::KOD_BLOCK){
$list = $listBlock->blockItems();
$current = $list[$pathParse['id']];
$current['name'] = _get($current,'name','root');
$current['icon'] = 'block-'.$pathParse['id'];
}else if($pathParse['type'] == KodIO::KOD_USER_FILE_TYPE){
$list = Action('explorer.listFileType')->block();
$current = $list[$pathParse['id']];
$current['name'] = LNG('common.fileType').' - '.$current['name'];
}else if($pathParse['type'] == KodIO::KOD_USER_FILE_TAG){
$list = Action('explorer.tag')->tagList();
$current = $list[$pathParse['id']];
$current['name'] = LNG('explorer.userTag.title').' - '.$current['name'];
}
$current['type'] = 'folder';
$current['path'] = $path;
return $current;
}
public function pathListParse(&$data){
$timeNow = timeFloat();
$timeMax = 2.5;
$infoFull= true;
$data['current'] = $this->pathInfoParse($data['current'],$data['current']);
foreach ($data as $type =>&$list) {
if(!in_array($type,array('fileList','folderList','groupList'))) continue;
foreach ($list as $key=>&$item){
if(timeFloat() - $timeNow >= $timeMax){$infoFull = false;}
$data[$type][$key] = $this->pathInfoParse($item,$data['current'],$infoFull);
};unset($item);
};unset($list);
$data = Hook::filter('explorer.list.path.parse',$data);
}
public function pathInfoParse($pathInfo,$current=false,$infoFull=true){
if(!$pathInfo) return false;
static $showMd5 = false; // 大量文件夹文件内容时,频繁调用性能优化;
static $explorerFav = false;
static $explorerTag = false;
static $explorerShare = false;
static $explorerTagGroup= false;
static $explorerDriver = false;
static $modelAuth = false;
if(!$explorerFav){
$explorerFav = Action('explorer.fav');
$explorerTag = Action('explorer.tag');
$explorerShare = Action('explorer.userShare');
$explorerTagGroup = Action('explorer.tagGroup');
$explorerDriver = Action('explorer.listDriver');
$explorerDriver = Action('explorer.listDriver');
$modelAuth = Model('Auth');
$showMd5 = Model('SystemOption')->get('showFileMd5') != '0';
}
if(USER_ID){
$explorerFav->favAppendItem($pathInfo);
$explorerTag->tagAppendItem($pathInfo);
$explorerShare->shareAppendItem($pathInfo);
$explorerTagGroup->tagAppendItem($pathInfo);
}
if($infoFull){
if( substr($pathInfo['path'],0,4) == '{io:'){
$explorerDriver->parsePathIO($pathInfo,$current);
}
if($pathInfo['type'] == 'folder' && !isset($pathInfo['hasFolder']) ){
$explorerDriver->parsePathChildren($pathInfo,$current);
}
if($pathInfo['type'] == 'file' && !$pathInfo['_infoSimple']){
$this->pathParseOexe($pathInfo);
$this->pathInfoMore($pathInfo);
}
}else{
if($pathInfo['type'] == 'folder'){
$pathInfo['hasFolder'] = true;
$pathInfo['hasFile'] = true;
}
}
if(!$pathInfo['pathDisplay']){$pathInfo['pathDisplay'] = $pathInfo['path'];}
// 下载权限处理;
if(!array_key_exists('isTruePath',$pathInfo)){
$pathInfo['isTruePath'] = KodIO::isTruePath($pathInfo['path']);
}
$pathInfo['canDownload'] = $pathInfo['isTruePath'];
if(isset($pathInfo['auth'])){
$pathInfo['canDownload'] = $modelAuth->authCheckDownload($pathInfo['auth']['authValue']);
}
// 写入权限;
if($pathInfo['isTruePath']){
if(isset($pathInfo['auth'])){
$pathInfo['canWrite'] = $modelAuth->authCheckEdit($pathInfo['auth']['authValue']);
}
if(is_array($pathInfo['metaInfo']) &&
isset($pathInfo['metaInfo']['systemLock']) &&
$pathInfo['metaInfo']['systemLock'] != USER_ID ){
$pathInfo['isWriteable'] = false;
}
}
if($pathInfo['type'] == 'file' && !$pathInfo['ext']){
$pathInfo['ext'] = strtolower($pathInfo['name']);
}
$pathInfo = $this->pathInfoCover($pathInfo);
// 没有下载权限,不显示fileInfo信息;
if(!$pathInfo['canDownload'] || !$showMd5){
if(isset($pathInfo['fileInfo'])){unset($pathInfo['fileInfo']);}
if(isset($pathInfo['hashMd5'])){unset($pathInfo['hashMd5']);}
}
if(isset($pathInfo['fileID'])){unset($pathInfo['fileID']);}
if(isset($pathInfo['fileInfo']['path'])){unset($pathInfo['fileInfo']['path']);}
return $pathInfo;
}
public function pathInfoCover($pathInfo){
// 文件文件夹封面; 自适应当前url;
if(is_array($pathInfo['metaInfo']) && $pathInfo['metaInfo']['user_sourceCover']){
$pathInfo['fileThumbCover'] = '1';
$pathInfo['fileThumb'] = Action('user.view')->parseUrl($pathInfo['metaInfo']['user_sourceCover']);
}
if($pathInfo['type'] == 'file'){ // 仅针对文件; 追加缩略图等业务;
$pathInfo = Hook::filter('explorer.list.itemParse',$pathInfo);
}
return $pathInfo;
}
/**
* 递归处理数据;自动加入打开等信息
* 如果是纯数组: 处理成 {folderList:[],fileList:[],thisPath:xxx,current:''}
*/
private function parseAuth(&$data,$path,$pathParse){
if( !isset($data['folderList']) ||
!is_array($data['folderList'])
) { //处理成统一格式
$listTemp = isset($data['fileList']) ? $data['fileList'] : $data;
$data = array(
"folderList" => $listTemp ? $listTemp : array(),
'fileList' => array()
);
}
if(!is_array($data['fileList'])){$data['fileList'] = array();}
if(!is_array($data['folderList'])){$data['folderList'] = array();}
$path = rtrim($path,'/').'/';
if(!isset($data['current']) || !$data['current']){
$data['current'] = $this->pathCurrent($path);
}
$data['thisPath'] = $path;
if(is_array($data['current']) && $data['current']['path']){
$data['thisPath'] = rtrim($data['current']['path'],'/').'/';
}
if(!$data['targetSpace']){
$data['targetSpace'] = $this->targetSpace($data['current']);
}
foreach ($data['folderList'] as &$item) {
if( isset($item['children']) ){
$item['isParent'] = true;
$pathParseParent = KodIO::parse($item['path']);
$this->parseAuth($item['children'],$item['path'],$pathParseParent);
}
$item['type'] = isset($item['type']) ? $item['type'] : 'folder';
};unset($item);
if($pathParse['type'] == KodIO::KOD_SHARE_LINK) return;
$data['fileList'] = $this->dataFilterAuth($data['fileList']);
$data['folderList'] = $this->dataFilterAuth($data['folderList']);
// 列表处理;
switch($pathParse['type']){
case KodIO::KOD_USER_FAV:
case KodIO::KOD_USER_RECENT:
case KodIO::KOD_GROUP_ROOT_SELF:
case KodIO::KOD_BLOCK:
$data['disableSort'] = 1;// 禁用客户端排序;
// $data['listTypeSet'] = 'list'; //强制显示模式;
break;
default:break;
}
}
// 显示隐藏文件处理; 默认不显示隐藏文件;
private function parseDataHidden(&$data,$pathParse){
if(Model('UserOption')->get('displayHideFile') == '1') return;
$pathHidden = Model('SystemOption')->get('pathHidden');
$pathHidden = explode(',',$pathHidden);
$hideNumber = 0;
if($pathParse['type'] == KodIO::KOD_USER_SHARE_TO_ME) return;
foreach ($data as $type =>$list) {
if(!in_array($type,array('fileList','folderList'))) continue;
$result = array();
foreach ($list as $item){
$firstChar = substr($item['name'],0,1);
if($firstChar == '.' || $firstChar == '~') continue;
if(in_array($item['name'],$pathHidden)) continue;
$result[] = $item;
}
$data[$type] = $result;
$hideNumber += count($list) - count($result);
}
}
// 用户或部门空间尺寸;
public function targetSpace($current){
if(!_get($current,'targetID')) return false;
if( isset($current['auth']) &&
$current['auth']['authValue'] == -1 ){
return false;
}
if(!$current || !isset($current['targetType'])){
$current = array("targetType"=>'user','targetID'=>USER_ID);//用户空间;
}
return Action('explorer.auth')->space($current['targetType'],$current['targetID']);
}
private function dataFilterAuth($list){
if($list && Action('explorer.auth')->allowRootSourceInfo($list[0])) return $list;
$shareLinkPre = '{shareItemLink';
foreach ($list as $key => $item) {
if( substr($item['path'],0,strlen($shareLinkPre)) == $shareLinkPre) continue;
if( isset($item['targetType']) &&
$item['targetType'] == 'user' &&
$item['targetID'] == USER_ID ){
continue;
}
// if(!isset($item['auth'])) continue;
if( isset($item['targetType']) &&
(!$item['auth'] || $item['auth']['authValue'] == 0 ) // 不包含-1,构建通路;
){
unset($list[$key]);
}
}
if(!is_array($list)) return array();
return array_values($list);
}
// 文件详细信息处理;
public function pathInfoMore(&$pathInfo){
if(!GetInfo::support($pathInfo['ext'])) return $pathInfo;
if($pathInfo['targetType'] == 'system') return $pathInfo;
$infoKey = 'fileInfoMore';
$cacheKey = md5($pathInfo['path'].'@'.$pathInfo['size'].$pathInfo['modifyTime']);
$fileID = _get($pathInfo,'fileID');
$fileID = _get($pathInfo,'fileInfo.fileID',$fileID);
if(!isset($pathInfo['sourceID'])){
$infoMore = Cache::get($cacheKey);
if(is_array($infoMore)){$pathInfo[$infoKey] = $infoMore;}
}
// 没有图片尺寸情况,再次计算获取;[更新]
$isImage = in_array($pathInfo['ext'],array('jpg','jpeg','png','ico','bmp'));
if($isImage && !isset($pathInfo[$infoKey]['sizeWidth'])){
unset($pathInfo[$infoKey]);
if(!isset($pathInfo['sourceID'])){Cache::remove($cacheKey);} //不使用缓存;
}
$debug = KodUser::isRoot() && $this->in['debug'] == '1'; // 调试模式,直接立即获取;
if($debug){
unset($pathInfo[$infoKey]);Cache::remove($cacheKey);//debug
if($fileID){Model("File")->metaSet($fileID,$infoKey,null);};
$infoMore = $this->pathInfoMoreParse($pathInfo['path'],$cacheKey,$fileID);
if(is_array($infoMore)){$pathInfo[$infoKey] = $infoMore;}
}
// 异步延迟获取;
$fileHash = $fileID ? $fileID : $cacheKey;
if(!isset($pathInfo[$infoKey]) || $pathInfo[$infoKey]['etag'] != $fileHash){
$args = array($pathInfo['path'],$cacheKey,$fileID);// 异步任务处理;
$desc = '[pathInfoMore]'.$pathInfo['name'];
$key ='pathInfoMoreParse-'.($fileID ? $fileID : $cacheKey);
TaskQueue::add('explorer.list.pathInfoMoreParse',$args,$desc,$key);
}
// md5 未计算情况处理;(队列加入失败,执行退出或文件不存在等情况补充)
if($fileID && is_array($pathInfo['fileInfo']) && !$pathInfo['fileInfo']['hashMd5']){
$fileInfo = Model("File")->fileInfo($fileID);
$args = array($fileID,$fileInfo);
$desc = '[fileMd5]'.$fileID.';path='.$pathInfo['path'];
TaskQueue::add('FileModel.fileMd5Set',$args,$desc,'fileMd5Set'.$fileID);
}
// 文件封面;
if(isset($pathInfo[$infoKey]) && isset($pathInfo[$infoKey]['fileThumb']) ){
$fileThumb = $pathInfo[$infoKey]['fileThumb'];
if(!IO::exist($fileThumb)){ // 不存在检测处理;
unset($pathInfo[$infoKey]);Cache::remove($cacheKey);
if($fileID){Model("File")->metaSet($fileID,$infoKey,null);};
return $pathInfo;
}
unset($pathInfo[$infoKey]['fileThumb']);
$pathInfo['fileThumb'] = Action('explorer.share')->linkFile($fileThumb);
}
return $pathInfo;
}
// 解析文件详情;
public function pathInfoMoreParse($file,$cacheKey,$fileID=false){
$infoKey = 'fileInfoMore';
$infoFull = IO::info($file);
unset($infoFull[$infoKey]);
GetInfo::infoAdd($infoFull);
$infoMore = isset($infoFull[$infoKey]) ? $infoFull[$infoKey]:false;
if(!$infoMore) return;
$infoMore['etag'] = $fileID ? $fileID : $cacheKey;
if($fileID){
Model("File")->metaSet($fileID,$infoKey,json_encode($infoMore));
}else{
Cache::set($cacheKey,$infoMore,3600*24*30);
}
return $infoMore;
}
// 获取文件内容, 存储在对象存储时不存在处理; 避免报错
private function pathGetContent($pathInfo){
if(!$pathInfo || !$pathInfo['path']){return "";}
$filePath = $pathInfo['path'];
if(isset($pathInfo['fileID'])){
$fileInfo = Model("File")->fileInfo($pathInfo['fileID']);
if(!$fileInfo || !$fileInfo['path']){return "";}
$filePath = $fileInfo['path'];
}
if(!IO::exist($filePath)){return "";}
return IO::getContent($filePath);
}
/**
* 追加应用内容信息;
*/
private function pathParseOexe(&$pathInfo){
$maxSize = 1024*1024*1;
if($pathInfo['ext'] != 'oexe' || $pathInfo['size'] > $maxSize) return $pathInfo;
if($pathInfo['size'] == 0) return $pathInfo;
if(!isset($pathInfo['oexeContent'])){
// 文件读取缓存处理; 默认缓存7天;
$pathHash = KodIO::hashPath($pathInfo);
$content = Cache::get($pathHash);
if(!$content){
$content = $this->pathGetContent($pathInfo);
Cache::set($pathHash,$content,3600*24*7);
}
if(!is_string($content) || !$content) return $pathInfo;
$pathInfo['oexeContent'] = json_decode($content,true);
}
if( $pathInfo['oexeContent']['type'] == 'path' &&
isset($pathInfo['oexeContent']['value']) ){
$linkPath = $pathInfo['oexeContent']['value'];
$parse = KodIO::parse($pathInfo['path']);
$parsePath = KodIO::parse($linkPath);
if($parse['type'] == KodIO::KOD_SHARE_LINK) return $pathInfo;
if(!$parsePath['isTruePath']){return $pathInfo;}
if(Action('explorer.auth')->fileCan($linkPath,'show')){
if(substr($linkPath,0,4) == '{io:'){ //io路径不处理;
$infoTarget = array('path'=>$linkPath);
$infoTarget = Action('explorer.listDriver')->parsePathIO($infoTarget);
}else{
$infoTarget = IO::info($linkPath);
}
$pathInfo['oexeSourceInfo'] = $infoTarget;
}
}
return $pathInfo;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/listBlock.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 文件列表通用入口获取
*/
class explorerListBlock extends Controller{
private $model;
public function __construct(){
parent::__construct();
$this->model = Model("Source");
}
/**
* 数据块数据获取
*/
public function blockChildren($type){
$result = array();
switch($type){
case 'root': $result = $this->blockRoot();break; //根
case 'files': $result = $this->blockFiles();break;
case 'tools': $result = $this->blockTools();break;
case 'safe': $result = Action('explorer.listSafe')->listRoot();break;
case 'fileType': $result = Action('explorer.listFileType')->block();break;
case 'fileTag': $result = Action('explorer.tag')->tagList();break;
case 'driver': $result = Action("explorer.listDriver")->get();break;
}
if(!is_array($result)) return array();
if(isset($result['folderList'])) return $result;
return array_values($result);
}
/**
* 根数据块
*/
private function blockRoot(){
$list = $this->blockItems();
if(!$this->pathEnable('fileType')){unset($list['fileType']);}
if(!KodUser::isRoot() || !$this->pathEnable('driver')){unset($list['driver']);}
if(!$this->pathEnable('fileTag')){unset($list['fileTag']);}
$result = array();
foreach ($list as $type => $item) {
$block = array_merge($item,array(
"path" => '{block:'.$type.'}/',
"isParent" => true,
));
if($block['open'] || $block['children']){
$block['children'] = $this->blockChildren($type);
if($block['children'] === false) continue;
} // 必须有children,没有children的去除(兼容Android <= 2.15)
$result[] = $block;
}
return $result;
}
public function blockItems(){
$list = array(
'files' => array('name'=>LNG('common.position'),'open'=>true),
'tools' => array('name'=>LNG('common.tools'),'open'=>true),
'fileType' => array('name'=>LNG('common.fileType'),'open'=>false,'children'=>true,'pathDesc'=> LNG('explorer.pathDesc.fileType')),
'fileTag' => array('name'=>LNG('explorer.userTag.title'),'open'=>false,'children'=>true,'pathDesc'=> LNG('explorer.pathDesc.tag')),
'driver' => array('name'=>LNG('common.mount').' (admin)','open'=>false,'pathDesc'=> LNG('explorer.pathDesc.mount')),
);
return $list;
}
private function groupRoot(){
$groupArray = Action('filter.userGroup')->userGroupRootShow();
if (!$groupArray || empty($groupArray[0])) return false;
return Model('Group')->getInfo($groupArray[0]);
}
/**
* 文件位置
* 收藏夹、我的网盘、公共网盘、我所在的部门
*/
private function blockFiles(){
$groupInfo = $this->groupRoot();
$list = array(
"fav" => array("path" => KodIO::KOD_USER_FAV,'pathDesc'=>LNG('explorer.pathDesc.fav')),
"my" => array(
'name' => LNG('explorer.toolbar.rootPath'),//我的网盘
'sourceRoot' => 'userSelf',//文档根目录标记;前端icon识别时用:用户,部门
"path" => KodIO::make(Session::get('kodUser.sourceInfo.sourceID')),
'open' => true,
'pathDesc' => LNG('explorer.pathDesc.home')
),
"rootGroup" => array(
'name' => $groupInfo['name'],
'sourceRoot' => 'groupPublic',
"path" => KodIO::make($groupInfo['sourceInfo']['sourceID']),
'pathDesc' => LNG('explorer.pathDesc.groupRoot')
),
"myGroup" => array("path" => KodIO::KOD_GROUP_ROOT_SELF,'pathDesc'=>LNG('explorer.pathDesc.myGroup')),
'shareToMe' => array("path" => KodIO::KOD_USER_SHARE_TO_ME),
);
$option = Model('SystemOption')->get();
if(!$this->pathEnable('myFav')){unset($list['fav']);}
if(!$this->pathEnable('my')){unset($list['my']);}
if(!$this->pathEnable('rootGroup') || !$groupInfo || !$groupInfo['sourceInfo']){unset($list['rootGroup']);}
if(!$this->pathEnable('myGroup')){unset($list['myGroup']);}
if($option['groupSpaceLimit'] == '1' && $option['groupSpaceLimitLevel'] <= 1){
unset($list['myGroup']);
}
// 根部门没有权限,且没有子内容时不显示;
if(isset($list['rootGroup'])){
$rootChildren = Action('explorer.list')->path($list['rootGroup']['path']);
$hasAuth = _get($rootChildren,'current.auth.authValue');
if(!$rootChildren['pageInfo']['totalNum'] && $hasAuth <= 0){
unset($list['rootGroup']);
}
}
// 没有所在部门时不显示;
if(isset($list['myGroup'])){
$selfGroup = Session::get("kodUser.groupInfo");
$groupArray = array_to_keyvalue($selfGroup,'','groupID');//自己所在的组
$group = array_remove_value($groupArray,$groupInfo['groupID']);
if(!$group && !isset($list['rootGroup'])){unset($list['myGroup']);}
if(!$selfGroup){unset($list['myGroup']);}
}
$explorer = Action('explorer.list');
$result = array();
foreach ($list as $pathItem){
$item = $explorer->pathCurrent($pathItem['path']);
if(!$item) continue;
$item['isParent'] = true;
if($item['open']){ //首次打开:默认展开的路径,自动加载字内容
$item['children'] = $explorer->path($item['path']);
}
$result[] = array_merge($item,$pathItem);
}
return $result;
}
public function pathEnable($type){
$model = Model('SystemOption');
$option = $model->get();
if( !isset($option['treeOpen']) ) return true;
// 单独添加driver情况;更新后处理; 单独加入文件类型开关,则根据flag标记;自动处理;
// my,myFav,myGroup,rootGroup,recentDoc,fileType,fileTag,userPhoto,driver
$checkType = array(
'treeOpenMy' => 'my',
'treeOpenMyGroup' => 'myGroup',
'treeOpenFileType' => 'fileType',
'treeOpenFileTag' => 'fileTag',
'treeOpenRecentDoc' => 'recentDoc',
'treeOpenPhoto' => 'userPhoto',
'treeOpenDriver' => 'driver',
'treeOpenFav' => 'myFav',
'treeOpenRootGroup' => 'rootGroup',
);
foreach ($checkType as $keyType=>$key){
if(isset($GLOBALS['TREE_OPTION_IGNORE']) && $GLOBALS['TREE_OPTION_IGNORE'] == '1') break;
if( $option[$keyType] !='ok'){
$model->set($keyType,'ok');
$model->set('treeOpen',$option['treeOpen'].','.$key);
$result = true;
$option = $model->get();
}
}
if($result) return true;
$allow = explode(',',$option['treeOpen']);
return in_array($type,$allow);
}
/**
* 工具
*/
private function blockTools(){
$list = $this->ioInfo(array(
KodIO::KOD_USER_RECENT,
KodIO::KOD_USER_SHARE,
KodIO::KOD_USER_SHARE_LINK,'userPhoto',
KodIO::KOD_USER_RECYCLE,
));
if(!$this->pathEnable('recentDoc')){
unset($list[KodIO::KOD_USER_RECENT]);
}
if(!$this->pathEnable('userPhoto')){
unset($list['userPhoto']);
}
if(Model('UserOption')->get('recycleOpen') == '0'){
unset($list[KodIO::KOD_USER_RECYCLE]);
}
if(Model('SystemOption')->get('shareLinkAllow') == '0'){
unset($list[KodIO::KOD_USER_SHARE_LINK]);
}
if(!is_array($list)) return array();
return array_values($list);
}
public function ioInfo($pick){
$list = array(
array(KodIO::KOD_USER_FAV,'explorer.toolbar.fav','explorer.pathDesc.fav'),
array(KodIO::KOD_GROUP_ROOT_SELF,'explorer.toolbar.myGroup','explorer.pathDesc.myGroup'),
array(KodIO::KOD_USER_RECENT,'explorer.toolbar.recentDoc','explorer.pathDesc.recentDoc'),
array(KodIO::KOD_USER_SHARE,'explorer.toolbar.shareTo','explorer.pathDesc.shareTo'),
array(KodIO::KOD_USER_SHARE_LINK,'explorer.toolbar.shareLink','explorer.pathDesc.shareLink'),
array(KodIO::KOD_USER_SHARE_TO_ME,'explorer.toolbar.shareToMe',''),
array(KodIO::KOD_USER_RECYCLE,'explorer.toolbar.recycle','explorer.pathDesc.recycle'),
array(KodIO::KOD_SEARCH,'common.search',''),
array('userPhoto',LNG('explorer.toolbar.photo'),LNG('explorer.photo.desc'),'{userFileType:photo}/'),
);
$result = array();
foreach ($list as $item){
$thePath = isset($item[3]) ? $item[3]:$item[0];
$result[$item[0]] = array(
"name" => LNG($item[1]),
"path" => $thePath.'/',
"pathDesc" => $item[2] ? LNG($item[2]) : '',
);
}
if(is_string($pick)){
return $result[$pick];
}else if(is_array($pick)){
$pickArr = array();
foreach ($pick as $value) {
$pickArr[$value] = $result[$value];
}
return $pickArr;
}
return $result;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/listDriver.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerListDriver extends Controller{
public function __construct(){
parent::__construct();
}
/**
* 用户存储挂载列表
*/
public function get(){
if(KodUser::isRoot()) return $this->rootList();
return false;//普通用户挂载暂不支持;
}
private function rootList(){
$GLOBALS['STORE_WITH_SIZEUSE'] = true;
$dataList = Model('Storage')->listData();
unset($GLOBALS['STORE_WITH_SIZEUSE']);
$list = array();
if($GLOBALS['config']['systemOption']['systemListDriver'] == '1'){
$diskList = KodIO::diskList(false);
foreach ($diskList as $path) {
$this->driverMake($list,$path);
}
}
foreach ($dataList as $item) {
$list[] = array(
"name" => $item['name'],
"path" => '{io:'.$item['id'].'}/',
"size" => $item['sizeUse'],
"driverSpace" => $item['sizeMax']*1024*1024*1024,
"driverDefault" => $item['default'],
"driverType" => $item['driver'],
"icon" => 'io-'.strtolower($item['driver']),
'isParent' => true,
);
}
$result = array('folderList' => $list, 'fileList'=>array());
$this->driverListGroup($result);
return $result;
}
// 对同一类型有多个存储的进行归类;
private function driverListGroup(&$result){
$notEqual = array('!='=>'1');
$groupShow = array(
array(
'type' => 'io-type-default',
'title' => LNG('admin.storage.current'),
"filter"=> array('driverDefault'=>array('='=>'1')),
)
);
if(count($result['folderList']) <= 5){
$groupShow[] = array(
'type' => 'io-type-others',
'title' => LNG('common.others'),
"filter"=> array('driverDefault'=>$notEqual),
);
$result['groupShow'] = $groupShow;
return;
}
$groupMinNumber = 3; // 超过数量才显示分组,否则归类到其他;
$driverOthers = array();
$listGroup = array_to_keyvalue_group($result['folderList'],'driverType');
foreach ($listGroup as $key=>$val){
if(count($val) < $groupMinNumber){
$driverOthers[] = $key;continue;
}
$langKey = 'admin.storage.'.strtolower($key);
$groupShow[] = array(
'type' => 'io-type-'.$key,
'title' => LNG($langKey) != $langKey ? LNG($langKey) : $key,
"filter"=> array('ioDriver'=>array('='=> $key),'driverDefault'=>$notEqual),
);
}
if(count($driverOthers) > 0){
$groupShow[] = array(
'type' => 'io-type-others',
'title' => LNG('common.others'),
"filter"=> array('ioDriver'=>array('in'=>$driverOthers),'driverDefault'=>$notEqual),
);
}
$result['groupShow'] = $groupShow;
}
public function parsePathIO(&$info,$current=false){
if(substr($info['path'],0,4) != '{io:') return $info;
static $driverList = false;
if ($driverList === false) {
$list = Model('Storage')->driverListSystem();
$driverList = array_to_keyvalue($list,'id');
}
if(!$driverList) return $info;
$isFavPath = false;
if(is_array($current) && isset($current['path'])){
$isFavPath = trim($current['path'],'/') == KodIO::KOD_USER_FAV;
}
$parse = KodIO::parse($info['path']);
$storage = $driverList[$parse['id']];
if(!$storage) return $info;
$storageName = str_replace("/",'-',$storage['name']);
$info['isReadable'] = array_key_exists('isReadable',$info) ? $info['isReadable'] : true;
$info['isWriteable'] = array_key_exists('isWriteable',$info) ? $info['isWriteable'] : true;
$info['pathDisplay'] = str_replace($parse['pathBase'],$storageName,$info['path']);
$langKey = 'admin.storage.'.strtolower($storage['driver']);
$info['ioType'] = LNG($langKey) != $langKey ? LNG($langKey) : $storage['driver'];
$info['ioDriver'] = $storage['driver'];
$info['ioIsSystem'] = (isset($storage['default']) && $storage['default'] == 1);
// 系统目录不允许写操作; 暂时屏蔽;
if($info['ioIsSystem'] && !GLOBAL_DEBUG){
if( preg_match("/{io:\d+}\/20\d\d[0-1][0-9]($|\/)/",$info['path'],$match) ||
preg_match("/{io:\d+}\/database($|\/)/i",$info['path'],$match)
){
$info['isReadable'] = false;
$info['isWriteable'] = false;
}
}
// 根目录;
$thePath = trim($parse['param'],'/');
if( (!$thePath && $thePath !== '0') || $isFavPath ){
$info['name'] = $storageName;
if($isFavPath){
$info['name'] = $info['sourceInfo']['favName'];
}
$info['icon'] = 'io-'.strtolower($storage['driver']);
if(isset($storage['config']['domain'])){
$info['ioDomain'] = $storage['config']['domain'];
}
if(isset($storage['config']['bucket'])){
$info['ioBucket'] = $storage['config']['bucket'];
}
if(isset($storage['config']['basePath'])){
$info['ioBasePath'] = $storage['config']['basePath'];
}
}
// pr($storage,$parse,$info,$driverList);exit;
return $info;
}
public function parsePathChildren(&$info,$current){
if($info['type'] == 'file' || isset($info['hasFolder']) ) return $info;
$ioAllow = array('Local');// array('Local','MinIO')
$pathParse = KodIO::parse($current['path']);
$isLocal = $pathParse['type'] ? false:true;
$isIoAllow = isset($current['ioType']) && in_array($current['ioType'],$ioAllow);
if($pathParse['type'] == KodIO::KOD_BLOCK && $pathParse['id'] != 'driver') return $info;
$infoMore = array('hasFolder'=>true,'hasFile'=> true);
if($isLocal || $isIoAllow){
$infoMore = IO::has($info['path'],1);
}else if($pathParse['type'] == KodIO::KOD_USER_FAV){
$itemParse = KodIO::parse($info['path']);
if(!$itemParse['type']){
$infoPath = IO::info($info['path']);
if(!$infoPath){
$infoMore = array('exists'=>false);
}else{
$infoMore = IO::has($info['path'],1);
$infoMore = is_array($infoMore) ? $infoMore : array();
$infoMore = array_merge($infoPath,$infoMore);
}
}
}
if(is_array($infoMore)){
unset($infoMore['name']);
$info = array_merge($info,$infoMore);
}
return $info;
}
private function driverMake(&$list,$path){
if(!file_exists($path)) return;
if(!function_exists('disk_total_space')){return;}
$total = @disk_total_space($path);
$list[] = array(
"name" => LNG('admin.storage.driver')."($path)",
"path" => $path,
"size" => $total - @disk_free_space($path),
"driverSpace" => $total,
"driverType" => 'Local',
"ioType" => LNG("admin.storage.driver"),
"ioDriver" => "Local",
"icon" => 'io-driver',
'isParent' => true,
);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/listFileType.class.php'
<?php
/**
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerListFileType extends Controller{
public function __construct(){
parent::__construct();
$this->model = Model("Source");
}
/**
* 文件类型列表
*/
public function block(){
$docType = KodIO::fileTypeList();
$list = array();
foreach ($docType as $key => $value) {
$list[$key] = array(
"name" => $value['name'],
"path" => KodIO::makeFileTypePath($key),
'ext' => $value['ext'],
'extType' => $key,
);
}
return $list;
}
public function get($type,$pathParse){
if($type == 'photo') return $this->getPhoto($pathParse);
return $this->model->listPathType($type);
}
private function getPhoto($pathParse){
$pageNum = $this->in['pageNum'];
$data = $this->listData($pathParse);
$this->groupData($data,$pageNum);
// 设置了分页时按路径保存在本地,不记录服务端; 默认500
$data['pageSizeArray'] = array(100,200,500,1000,2000,5000);
$data['disableSort'] = 1; // 禁用客户端排序;
$data['listTypePhoto'] = 1; // 强制显示图片模式;
$data['listTypeSet'] = 'icon'; // 强制显示模式;
return $data;
}
// 默认个人空间; 可扩展到任意文件夹相册模式;
private function listData($pathParse){
$search = Action('explorer.listSearch');
$sizeFrom = 100;
$homePath = MY_HOME;
$fileType = 'jpg,jpeg,png,gif,bmp,heic,webp,mov,mp4';// livp;
$option = json_decode(Model("UserOption")->get('photoConfig'),true);
if(is_array($option)){
if(isset($option['pathRoot'])){$homePath = $option['pathRoot'];}
if(isset($option['fileSize'])){$sizeFrom = intval($option['fileSize']) * 1024;}
if(isset($option['fileType'])){$fileType = $option['fileType'];}
}
$thePath = rtrim($pathParse['param'],'/');
$thePath = $thePath ? $thePath : $homePath;
if(substr($thePath,0,2) == '/{'){$thePath = substr($thePath,1);}
if(!Action('explorer.auth')->fileCanRead($thePath)){
$errorTips = LNG('explorer.noPermissionAction'); //指定目录无权限或不存在处理;
$destInfo = IO::info($thePath);
if(!$destInfo || $destInfo['pathType'] == "{systemRecycle}"){
$errorTips = LNG('common.pathNotExists');
}
$result = array("fileList"=>array(),'folderList'=>array());
$result['current'] = $this->photoCurrent($pathParse,$thePath);
$result['folderTips'] = $errorTips;
show_json($result,true);
}
$this->in['pageNum'] = 20000; // 最多查询数量;
$param = array('parentPath'=>$thePath,'fileType'=>$fileType);
if($sizeFrom > 0){$param['sizeFrom'] = $sizeFrom;}
$param['parentID'] = $search->searchPathSource($thePath);
$result = $search->searchData($param);
$result['current'] = $this->photoCurrent($pathParse,$thePath);
return $result;
}
private function photoCurrent($pathParse,$thePath){
$option = json_decode(Model("UserOption")->get('photoConfig'),true);
$thePath = rtrim($pathParse['param'],'/');
$pathAddress = array(array('name' =>LNG('explorer.toolbar.photo'),'path'=>$pathParse['path']));
$pathDesc = LNG('explorer.photo.desc');
if($thePath){
$thePath = substr($thePath,0,2) == '/{' ? ltrim($thePath,'/') : $thePath;
$info = IO::info($thePath);
$pathAddress[0]['name'] = LNG('explorer.toolbar.folder').' - '.$info['name'];
$pathAddress[] = array('name' =>trim($info['pathDisplay'],'/'),'path'=>$thePath);
$pathDesc = $info['pathDisplay'] ? $info['pathDisplay']: $info['path'];
}else if(is_array($option)){
if(isset($option['pathRootShow'])){$pathDesc .= '<br/>'.LNG('explorer.photo.pathRoot').': '.$option['pathRootShow'];}
}
if(is_array($option)){
if(isset($option['fileType'])){$pathDesc .= '<br/>'.LNG('explorer.photo.fileType').': '.$option['fileType'];}
}
$result = array(
'path' => $pathParse['path'],
'name' => $pathAddress[0]['name'],
'pathDesc' => $pathDesc,
'type' => 'folder',
'pathAddress' => $pathAddress,
);
return $result;
}
// 数据分组
private function groupData(&$data,$pageNum){
$this->resetImageTime($data);
$fileList = array_sort_by($data['fileList'],'imageTime',true);
$groupBy = Input::get('photoListBy','in','month',array('year','month','day'));// 分组类型
$pageNum = intval($pageNum) <= 100 ? 100 : intval($pageNum);
$pageTotal = ceil(count($fileList) / $pageNum);
$page = isset($this->in['page']) ? intval($this->in['page']) : 1;
$page = $page <= 1 ? 1 : ($page >= $pageTotal ? $pageTotal : $page);
$groupArray = array();
$listPage = array_slice($fileList,$pageNum * ($page - 1),$pageNum);
$groupTypeArr = array(
'year' => array('Y','-01-01 00:00:00',' +1 year'),
'month' => array('Y-m','-01 00:00:00', ' +1 month'),
'day' => array('Y-m-d',' 00:00:00', ' +1 day'),
);
$groupType = $groupTypeArr[$groupBy];
foreach($listPage as $file){
$key = date($groupType[0],$file['imageTime']);
if(!isset($groupArray[$key])){
$timeStart = strtotime($key.$groupType[1]);
$timeTo = strtotime(date('Y-m-d H:i:s',$timeStart).$groupType[2]);
$groupArray[$key] = array(
'type' => 'photo-group-'.$timeStart,
'title' => $key,
"desc" => '', 'count'=> 0,
"filter"=> array('imageTime'=>array('>'=> $timeStart,'<'=> $timeTo)),
);
}
$groupArray[$key]['count'] += 1;
$groupArray[$key]['desc'] = $groupArray[$key]['count'] .' '. LNG('common.items');
}
// pr($groupArray,$page,$pageTotal);exit;
$data['fileList'] = $listPage;
$data['groupShow'] = array_values($groupArray);
$data['pageInfo'] = array('page'=>$page,'pageTotal'=>$pageTotal,'totalNum'=>count($fileList),'pageNum'=>$pageNum);
}
// 图片时间处理, 优先级: 拍摄时间>本地最后修改时间>上传时间
public function resetImageTime(&$data){
foreach($data['fileList'] as &$file){
$file['imageTime'] = intval($file['modifyTime']);
if(is_array($file['fileInfoMore']) && isset($file['fileInfoMore']['createTime'])){
$file['imageTime'] = strtotime($file['fileInfoMore']['createTime']);
if($file['imageTime']){continue;}
}
if(is_array($file['metaInfo']) && isset($file['metaInfo']['modifyTimeLocal'])){
$file['imageTime'] = intval($file['metaInfo']['modifyTimeLocal']);
}
$file['imageTime'] = intval($file['modifyTime']);
};unset($file);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/listGroup.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerListGroup extends Controller{
public function __construct(){
parent::__construct();
$this->model = Model("Source");
$this->modelGroup = Model('Group');
}
public function groupSelf($pathInfo){//获取组织架构的用户和子组织;
$groupArray = Session::get("kodUser.groupInfo");
$groupArray = array_sort_by($groupArray,'groupID');
$groupArray = $this->groupSelfLimit($groupArray);
$listData = $this->groupArray($groupArray);
$this->groupSelfAppendAllow($listData);
return $listData;
}
// 我所在的部门, 罗列自己有权限的部门(通路)
public function groupSelfAppendAllow(&$listData){
if(intval($this->in['page']) > 1) return;// 第一页才罗列;
if(isset($this->in['fromType']) && $this->in['fromType']=='tree'){return;} // 树目录不显示,仅在文件区域显示;
$groupArray = Action('filter.userGroup')->userGroupRootShow();
if(!$groupArray || empty($groupArray[0])) return false;
$groupList = array();$groupListArr = array();
foreach ($listData as $key => $item) {
$item['sourceRootSelf'] = 'self';
$groupList[] = $item;
$groupListArr[$item['targetID']] = $item;
unset($listData[$key]);
}
$groupChild = $this->modelGroup->where(array('parentID'=>$groupArray[0]))->select();
$groupAdd = $this->groupArray($groupChild);
$groupAddTo = array();// 去除重复已在该部门的部门;
foreach ($groupAdd as $item){
if(isset($groupListArr[$item['targetID']])){continue;}
$groupAddTo[] = $item;
}
$listData['groupList'] = $groupList;
$listData['folderList']= $groupAddTo;
$desc = '('.LNG('explorer.toolbar.myGroupAllowDesc').')';
$listData['groupShow'] = array(
array('type'=>'childGroupSelf', 'title'=>LNG('explorer.toolbar.myGroup'),"filter"=>array('sourceRootSelf'=>'self')),
array('type'=>'childGroupAllow','title'=>LNG('explorer.toolbar.myGroupAllow'),"desc"=>$desc,"filter"=>array('sourceRootSelf'=>'!=self')),
);
if(count($listData['folderList']) == 0){unset($listData['groupShow']);}
}
// 部门层级限制处理; 超过层级限制的部门,展示该部门在限制层级时的部门通路;
private function groupSelfLimit($groupArray){
$option = Model('SystemOption')->get();
if($option['groupSpaceLimit'] != '1') return $groupArray;
$levelMax = intval($option['groupSpaceLimitLevel']);
$groupMap = array_to_keyvalue($groupArray,'groupID');
$groupArray = array();
foreach ($groupMap as $groupID => $item) {
$level = explode(',',trim($item['parentLevel'],',')); // -1 + 1(去掉0;加上自己; 最后一层是自己)
if(count($level) <= $levelMax){$groupArray[$groupID] = $item;continue;}
$autoGroupID = $level[$levelMax];
if(!isset($groupMap[$autoGroupID])){
$info = $this->modelGroup->getInfoSimple($autoGroupID);
$groupMap[$autoGroupID] = array(
'groupID' => $info['groupID'],
'groupName' => $info['name'],
'parentLevel' => $info['parentLevel']
);
}
if(!is_array($groupMap[$autoGroupID])){continue;}
$groupArray[$autoGroupID] = $groupMap[$autoGroupID];
}
// pr($groupMap,$groupArray);exit;
return $groupArray;
}
// 是否允许罗列部门的子部门;
private function enableListGroup($groupID,&$data){
$option = Model('SystemOption')->get();
if($option['groupSpaceLimit'] == '1'){
$groupInfo = $this->modelGroup->getInfoSimple($groupID);
$level = explode(',',trim($groupInfo['parentLevel'],',')); // -1 + 1(去掉0;加上自己)
if(count($level) >= intval($option['groupSpaceLimitLevel'])){return false;}
}
if( !isset($option['groupListChild']) ) return true;
// 仅左侧树目录罗列子部门,不罗列文件文件夹; 文件区域不罗列子部门,仅罗列文件文件夹;
// app 忽略树目录设定; 编辑请求忽略树目录设定;
if($option['groupListChild'] == '2'){
$device = Action('filter.userCheck')->getDevice();
if($device && $device['type'] == 'app'){return true;} // app忽略此设定;
if(isset($this->in['listTree']) && $this->in['listTree'] == 'all'){return true;}
if($this->in['fromType'] == 'tree'){
$data['folderList'] = array();$data['fileList'] = array();
return true;
}
return false;
}
$listGroup = $option['groupListChild']=='1';
if(!$listGroup) return false;
if($groupID == '1'){
return is_null($option['groupRootListChild']) || $option['groupRootListChild']=='1';
}
return true;
}
// 根据多个部门信息,构造部门item;
private function groupArray($groupArray){
$groupArray = array_sort_by($groupArray,'sort');// 排序处理;
$groupArray = array_to_keyvalue($groupArray,'groupID');//自己所在的组
$this->_filterDisGroup($groupArray); // 过滤已禁用部门
$group = array_keys($groupArray);
if(!$group) return array();
// 部门目录是否显示子部门; 0 不显示;1 全部显示;2=仅树目录显示
$isFromTree = isset($this->in['fromType']) && $this->in['fromType']=='tree';
$groupListType = Model('SystemOption')->get('groupListChild');
if(isset($this->in['listTree']) && $this->in['listTree'] == 'all'){
$isFromTree = false;$groupListType = '1';
}
$groupSource = $this->model->sourceRootGroup($group);
$groupSource = array_to_keyvalue($groupSource,'targetID');
$result = array();
foreach($groupArray as $group){ // 保持部门查询结构的顺序;
$groupID = $group['groupID'];
if($groupID == '1'){// 去除根部门(未禁用显示企业网盘时去除)
if(Action('explorer.listBlock')->pathEnable('rootGroup')){continue;}
}
if(!isset($groupSource[$groupID])) continue;
$groupInfo = Model('Group')->getInfo($groupID);
$pathInfo = $groupSource[$groupID];
$pathInfo['sourceRoot'] = 'groupPath';
$pathInfo['hasGroup'] = $groupInfo ? $groupInfo['hasChildren']:0;
$pathInfo['pathDisplay']= $pathInfo['groupPathDisplay'];
if(!$pathInfo['auth']){
$pathInfo['auth'] = Model("SourceAuth")->authDeepCheck($pathInfo['sourceID']);
}
// 部门根目录是否有文件夹取决于[有文件夹,或有子部门]; 后台设置--仅树目录显示子部门时,是否可展开取决于是否有子部门;
$pathInfo['hasFolder'] = $pathInfo['hasFolder'] || $pathInfo['hasGroup'];
if($isFromTree && $groupListType == '2'){
$pathInfo['hasFolder'] = $pathInfo['hasGroup'];
$pathInfo['hasFile'] = false;
}
$userRootShow = KodUser::isRoot() && $GLOBALS['config']["ADMIN_ALLOW_SOURCE"];
if(!$userRootShow){
if( !$pathInfo['auth'] || $pathInfo['auth']['authValue'] == 0){ // 放过-1; 打开通路;
continue;// 没有权限;
}
}
$result[] = $pathInfo;
}
// pr($result,$groupSource,$group,$groupArray);exit;
return $result;
}
// 过滤已禁用部门
private function _filterDisGroup(&$list){
if(empty($list)) return array();
$where = array(
'groupID' => array('in', array_keys($list)),
'key' => 'status',
'value' => 0
);
$data = Model('group_meta')->where($where)->field('groupID')->select();
foreach($data as $value) {
unset($list[$value['groupID']]);
}
}
/**
* 部门根目录;罗列子部门;
*/
public function appendChildren(&$data){
$pathInfo = $data['current'];
if(!$pathInfo || _get($pathInfo,'targetType') != 'group') return false;
if(isset($pathInfo['shareID'])) return false;
if(intval($this->in['page']) > 1) return;// 第一页才罗列;
//不是根目录
$parents = $this->model->parentLevelArray($pathInfo['parentLevel']);
if(count($parents) != 0) return false;
if(!$this->enableListGroup($pathInfo['targetID'],$data)) return;
$groupList = $this->modelGroup->where(array('parentID'=>$pathInfo['targetID']))->select();
$groupListAdd = $this->groupArray($groupList);
$data['pageInfo']['totalNum'] += count($groupListAdd);
$data['groupList'] = $groupListAdd;
$data['groupShow'] = array(
array('type'=>'childGroup','title'=>LNG('explorer.pathGroup.group'),"filter"=>array('sourceRoot'=>'groupPath')),
array('type'=>'childContent','title'=>LNG('explorer.pathGroup.groupContent'),"filter"=>array('sourceRoot'=>'!=groupPath')),
);
if(count($data['groupList']) == 0){unset($data['groupShow']);}
// show_json($data);exit;
}
public function pathGroupAuthMake($groupID,$userID=false){
$groupRoot = '1';
$groupInfo = $this->modelGroup->getInfoSimple($groupID);//101
if(!$userID){
$groupSelf = Session::get("kodUser.groupInfo");
}else{
$userInfo = Model('User')->getInfo($userID);
$groupSelf = $userInfo['groupInfo'];
}
if(!$groupSelf) return false;
// 部门文件夹或子文件夹没有针对自己设置权限,向上级部门回溯;
$groupSelf = array_to_keyvalue($groupSelf,'groupID');//自己所在的组
$parents = $this->model->parentLevelArray($groupInfo['parentLevel']);
$parents[] = $groupID;
$parents = array_reverse($parents);
foreach ($parents as $id) {
if($id == $groupRoot) return false;// 根部门;
if(isset($groupSelf[$id])){
return array(
'authValue' => intval($groupSelf[$id]['auth']['auth']),
'authInfo' => $groupSelf[$id]['auth'],
);
}
}
return Model("SourceAuth")->authDeepCheck($groupInfo['sourceInfo']['sourceID'],$userID);
}
/**
* 用户根目录,部门根目录操作检测
* 不允许: 重命名,删除,复制,剪切,下载,分享
*/
public function pathRootCheck($action){
$disable = array(
'path' => array(
'explorer.index.pathRename',
'explorer.userShare.add',
'explorer.userShare.get',
'explorer.userShare.edit',
),
'dataArr'=> array(
'explorer.index.pathDelete',
'explorer.index.pathCopy',
'explorer.index.pathCute',
'explorer.index.pathCopyTo',
'explorer.index.pathCuteTo',
'explorer.index.zipDownload'
),
);
foreach ($disable as $type=>$medhods) {
$disable[$type] = array();
foreach ($medhods as $item) {
$disable[$type][] = strtolower($item);
}
}
$allAction = array_merge($disable['path'],$disable['dataArr']);
if(!in_array($action,$allAction)) return;
$isGroupRoot = false;
$errorAdd = '';
if(in_array($action,$disable['path'])){
$isGroupRoot = $this->pathIsRoot($this->in['path']);
}else{
$data = json_decode($this->in['dataArr'],true);
if(is_array($data)){
foreach ($data as $item) {
$isGroupRoot = $this->pathIsRoot($item['path']);
if($isGroupRoot){
$errorAdd = '['.$item['name'].'],';
break;
}
}
}
}
if(!$isGroupRoot) return;
return show_json($errorAdd.LNG('explorer.pathNotSupport'),false);
}
// 检测目录是否为部门根目录;
private function pathIsRoot($path){
$parse = KodIO::parse($path);
if($parse['type'] != KodIO::KOD_SOURCE) return false;
$info = IO::infoSimple($path);
if($info['targetType'] != SourceModel::TYPE_GROUP) return false;
if($info['targetType'] != SourceModel::TYPE_USER) return false;
if($info['parentID'] =='0') return true;//部门根目录,用户根目录;
// if(!$info || $info['targetType'] != 'group') return false;
return false;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/listPassword.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 加密文件夹处理
*/
class explorerListPassword extends Controller{
private $model;
public function __construct(){
parent::__construct();
$this->model = Model("Source");
}
// 权限检测
public function authCheck($pathInfo,$action){
if(!$this->checkAuthNeed($pathInfo)){return;} // 拥有编辑以上权限则忽略;
$passInfo = $this->checkAllowPassword($pathInfo);
if($passInfo){// 当前文件,或上层需要密码;
if($action == 'show'){return;}
return LNG('explorer.folderPass.tips');
}
// 查询子目录是否包含需要设置密码的文件夹;
if($pathInfo['type'] == 'folder' && $action == 'download'){
$where = array(
"source.parentLevel"=> array("like",$pathInfo['parentLevel'].$pathInfo['sourceID'].',%'),
"source.isDelete" => 0,
"meta.key" => 'folderPassword',
);
$field = "source.sourceID,meta.value";
$join = "LEFT JOIN io_source_meta meta on source.sourceID = meta.sourceID";
$list = $this->model->alias("source")->field($field)->where($where)->join($join)->select();
$sourceMeta = $this->folderPasswordMeta(array_to_keyvalue($list,'','sourceID'));
$needPassword = array();
foreach($sourceMeta as $sourceID => $passInfo){
$sessionKey = "folderPassword_".$passInfo['sourceID'];
if( $passInfo && Session::get($sessionKey) != $passInfo['folderPassword']){
$needPassword[] = $passInfo;
}
}
// trace_log([$passInfo,$pathInfo,$action,$list,$needPassword]);
$msgCount = ' ['.count($needPassword).' '.LNG('common.items').']';
if($needPassword){return LNG('explorer.folderPass.tipsHas').$msgCount;}
}
}
// 追加到根目录;
public function appendSafe(&$data){
$passInfo = $this->checkAllowPassword($data['current']);
if(!$passInfo){return;}
unset($passInfo['folderPassword']);
$data['fileList'] = array();
$data['folderList'] = array();
$data['folderTips'] = LNG('explorer.folderPass.tips').";".htmlentities($passInfo['folderPasswordDesc']);
$data['pathDesc'] = $data['folderTips'];
$data['folderPasswordNeed'] = $passInfo;
}
private function checkAuthNeed($pathInfo){
if(!$pathInfo || empty($pathInfo['sourceID']) || empty($pathInfo['parentLevel'])){return false;}
$canEdit = is_array($pathInfo['auth']) ? Model("Auth")->authCheckEdit($pathInfo['auth']['authValue']):false;
$userSelf = $pathInfo['targetType'] == 'user' && $pathInfo['targetID'] == KodUser::id();
if($userSelf || $canEdit || KodUser::isRoot()){return false;}
return true;
}
private function checkAllowPassword($pathInfo){
if(!$this->checkAuthNeed($pathInfo)){return false;}
$passInfo = $this->folderPasswordFind($pathInfo);
if(!$passInfo){return false;}
$sessionKey = "folderPassword_".$passInfo['sourceID'];
if( $passInfo && !empty($this->in['folderPassword']) &&
$this->in['folderPassword'] == $passInfo['folderPassword']){
Session::set($sessionKey,$passInfo['folderPassword']);
$passInfo = false;// 输入密码正确;
}
if( $passInfo && Session::get($sessionKey) == $passInfo['folderPassword']){
$passInfo = false;// 回话中存在密码,且一致;
}
return $passInfo;
}
// 向上查找上层文件夹包含密码设置的文件夹(上级多层包含密码时,仅匹配最近的一层密码设置; )
private function folderPasswordFind($pathInfo){
static $_cache = array();
$keys = array('folderPassword','folderPasswordDesc','folderPasswordTimeTo','folderPasswordUser');
$parentLevel = $this->model->parentLevelArray($pathInfo['parentLevel']);
$parentLevel[] = $pathInfo['sourceID'];
$parentLevel = array_reverse($parentLevel);
$findHas = false;
foreach($parentLevel as $sourceID){
if(empty($_cache[$sourceID])){continue;}
$findHas = $_cache[$sourceID];break;
}
if($findHas || isset($_cache[$pathInfo['sourceID']])){return $findHas;}
$sourceMeta = $this->folderPasswordMeta($parentLevel);
foreach ($sourceMeta as $sourceID => $meta) {
$_cache[$sourceID] = $meta;
}
foreach($parentLevel as $sourceID){
if(empty($_cache[$sourceID])){continue;}
$findHas = $_cache[$sourceID];break;
}
return $findHas;
}
private function folderPasswordMeta($sourceArr){
$sourceMeta = array();
if(!$sourceArr){return $sourceMeta;}
$keys = array('folderPassword','folderPasswordDesc','folderPasswordTimeTo','folderPasswordUser');
$where = array('sourceID'=>array('in',$sourceArr),'key'=>array('in',$keys));
$metaArr = Model('io_source_meta')->where($where)->select();
$metaArr = array_to_keyvalue_group($metaArr,'sourceID');
foreach($metaArr as $sourceID=>$theMeta){
$meta = array_to_keyvalue($theMeta,'key','value');
if(empty($meta['folderPassword'])){$meta = array();}
if(!empty($meta['folderPasswordTimeTo']) && $meta['folderPasswordTimeTo'] < time() ){ //已过期处理;
$meta = array();
}
if(!empty($meta['folderPasswordUser'])){
$item['value'] = Model("User")->getInfoSimpleOuter($meta['folderPasswordUser']);
}
if(!empty($meta)){$meta['sourceID'] = $sourceID;}
$sourceMeta[$sourceID] = $meta;
}
return $sourceMeta;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/listRecent.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerListRecent extends Controller{
public function __construct(){
$this->model = Model("Source");
parent::__construct();
}
/**
* 最近文档;
* 仅限自己的文档;不分页;不支持排序; 最新修改时间 or 最新修改 or 最新打开 max top 100;
*
* 最新自己创建的文件(上传or拷贝)
* 最新修改的,自己创建的文件
* 最新打开的自己的文件
*
* 资源去重;整体按时间排序【创建or上传 修改 打开】
*/
public function listData(){
$list = array();
$this->listRecentWith('createTime',$list); //最近上传or创建
$this->listRecentWith('modifyTime',$list); //最后修改
$this->listRecentWith('viewTime',$list); //最后打开
//合并重复出现的类型;
foreach ($list as &$value) {
$value['recentType'] = 'createTime';
$value['recentTime'] = $value['createTime'];
if($value['modifyTime'] > $value['recentTime']){
$value['recentType'] = 'modifyTime';
$value['recentTime'] = $value['modifyTime'];
}
if($value['viewTime'] > $value['recentTime']){
$value['recentType'] = 'viewTime';
$value['recentTime'] = $value['viewTime'];
}
$value['recentTime'] = intval($value['recentTime']);
};unset($value);
$list = array_sort_by($list,'recentTime',true);
$listRecent = array_to_keyvalue($list,'sourceID');
$result = array();
if(!empty($listRecent)){
$where = array( 'sourceID'=>array('in',array_keys($listRecent)) );
$result = $this->model->listSource($where);
}
$fileList = array_to_keyvalue($result['fileList'],'sourceID');
//保持排序,合并数据
foreach ($listRecent as $sourceID => &$value) {
$item = $fileList[$sourceID];
if(!$item){
unset($listRecent[$sourceID]);
continue;
}
$value = array_merge($value,$item);
}
$result['fileList'] = array_values($listRecent);
$todayStart = strtotime(date('Y-m-d 00:00:00'));
$dayTime = 24 * 3600;
$result['groupShow'] = array(
array(
'type' => 'time-today',
'title' => LNG("common.date.today"),
"desc" => date("Y-m-d",time()),
"filter"=> array('recentTime'=>array('>'=> $todayStart )),
),
array(
'type' => 'time-yesterday',
'title' => LNG("common.date.yestoday"),
"desc" => date("Y-m-d",$todayStart - $dayTime),
"filter"=> array('recentTime'=>array('<'=> $todayStart,'>'=> $todayStart - $dayTime )),
),
array(
'type' => 'time-before',
'title' => LNG('common.date.before'),
"filter"=> array('recentTime'=>array('<'=> $todayStart - $dayTime )),
),
);
return $result;
}
private function listRecentWith($timeType,&$result){
$userID = USER_ID;
$userInfo = Model('User')->getInfo($userID);
$where = array(
'targetType' => SourceModel::TYPE_USER,
'targetID' => $userID,
'parentLevel' => array("like",',0,'.$userInfo['sourceInfo']['sourceID'].',%'),
'isFolder' => 0,
'isDelete' => 0,
'size' => array('>',0),
);
// 内部协作分享,修改上传内容; 普通用户可能没有权限进入处理;
if(KodUser::isRoot()){
if(in_array($timeType,array('createTime','modifyTime')) ){
unset($where['targetID']);
$where['targetType'] = array('in',array(SourceModel::TYPE_USER,SourceModel::TYPE_GROUP));
}
if($timeType == 'createTime'){$where['createUser'] = $userID;}
if($timeType == 'modifyTime'){$where['modifyUser'] = $userID;}
}
$where[$timeType] = array(
array('>',time() - 3600*24*60),//2个月内
array('<',time()),// 忽略大于当前时间内容;
);
$maxNum = 50; //最多150项
$field = 'sourceID,name,createTime,modifyTime,viewTime';
$list = $this->model->field($field)->where($where)
->limit($maxNum)->order($timeType.' desc')->select();
$list = array_to_keyvalue($list,'sourceID');
$result = array_merge($result,$list);
$result = array_to_keyvalue($result,'sourceID');
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/listSafe.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 私密保险箱处理(个人根目录置顶; 状态:未启用,启用-已授权/未授权)
*
* 根目录权限:不支持:复制/剪切/重命名/拖拽;
* 子内容权限:不能外链分享/协作分享/收藏/添加标签/发送到桌面快捷方式; 不能通过用户根目录搜索;
*/
class explorerListSafe extends Controller{
private $model;
public function __construct(){
parent::__construct();
$this->model = Model("Source");
}
// 权限检测
public function authCheck($pathInfo,$action){
if(!isset($pathInfo['sourceAt']) || $pathInfo['sourceAt'] != 'pathSafeSpace'){return;}
$spaceInfo = $this->spaceInfo();
if($spaceInfo['type'] != 'isLogin'){
if(ACTION == 'explorer.list.path'){show_json($spaceInfo['listEmpty'],true);}
return LNG('explorer.safe.isNotLogin');
}
$notAllowAction = array('share'); // 保险箱内内容不支持的操作: 分享编辑/删除;
if(in_array($action,$notAllowAction)){return LNG('explorer.pathNotSupport');}
return false;
}
// 保险箱内内容不支持的操作;sourceID 路径检测(主动调用)
public function authCheckAllow($path){
if(!is_numeric($path) || !$path){return;}
$pathInfo = $this->model->pathInfo($path);
if(!$pathInfo || $pathInfo['sourceAt'] != 'pathSafeSpace'){return;}
show_json(LNG('explorer.pathNotSupport'),false);
}
// 追加到根目录;
public function appendSafe(&$data){
$this->appendSafeChildren($data);
$this->appendSafeUserRootAdmin($data);
$pathInfo = $data['current'];
if(!$pathInfo || intval($this->in['page']) > 1) return false;
if(!isset($pathInfo['targetType']) || !isset($pathInfo['targetID']) || !isset($pathInfo['parentID'])){return;}
if($pathInfo['parentID'] != 0 || $pathInfo['targetType'] != 'user' || $pathInfo['targetID'] != USER_ID) return;
if(defined('KOD_FROM_WEBDAV')){return;}
$userInfo = Model("User")->getInfoFull(USER_ID);
if(_get($data,'current.sourceID') == _get($userInfo,'metaInfo.pathSafeFolder')) return;
if(_get($data,'current.sourceID') != _get($userInfo,'sourceInfo.sourceID')) return; // 仅个人空间根目录下显示
if(Model("UserOption")->get('pathSafeSpaceShow') != '1'){return;} // 个人设置已隐藏;
$spaceInfo = $this->spaceInfo();
// 系统全局关闭,且自己未启用时不显示;
if(Model("SystemOption")->get('pathSafeSpaceEnable') != '1'){
if($spaceInfo['type'] == 'isNotOpen'){return;}
// return;
}
$data['folderList'][] = $spaceInfo['folderRoot'];
}
// 私密空间子列表处理(未登录提示登录; 已登录子内容追加标记)
private function appendSafeChildren(&$data){
$pathInfo = $data['current'];
// 私密保险箱根目录, 追加应用根目录入口;
if($pathInfo['parentID'] == 0 && _get($pathInfo,'metaInfo.pathSafeFolderUser')){
$userInfo = Model('User')->getInfoFull($pathInfo['targetID']);
$userAppRoot = _get($userInfo,'metaInfo.pathAppRoot','');
if($userAppRoot){
$data['folderList'][] = array(
'name' => LNG('explorer.appFolder'),
'path' => '{source:'.$userAppRoot.'}/',
'icon' => 'kod-box',//kod-box kod-folder2
'type' => 'folder','pathReadOnly'=>true,
'pathDesc' => LNG('explorer.appFolder'),
'metaInfo' => array('systemSort'=>3000000000,'systemSortHidden'=>true),
);
}
}
if(!isset($pathInfo['sourceAt']) || $pathInfo['sourceAt'] != 'pathSafeSpace'){return;}
$spaceInfo = $this->spaceInfo();
if($spaceInfo['type'] != 'isLogin'){ // 未登录访问拦截;
return show_json($spaceInfo['listEmpty'],true);
}
foreach ($data['fileList'] as &$item){
$item['sourceAt'] = 'pathSafeSpace';
};unset($item);
foreach ($data['folderList'] as &$item){
$item['sourceAt'] = 'pathSafeSpace';
};unset($item);
}
// 系统管理员: 管理用户根目录--显示私密文件夹处理(默认关闭)
private function appendSafeUserRootAdmin(&$data){
if(!$this->config["ADMIN_ALLOW_USER_SAFE"]){return;}
$pathInfo = $data['current'];
if(!KodUser::isRoot() || !$pathInfo || !$pathInfo['sourceID']){return;}
if($pathInfo['parentID'] != 0 || $pathInfo['targetType'] != 'user') return;
if($pathInfo['targetID'] == USER_ID) return;//自己的根目录;
$userInfo = $userInfo = Model("User")->getInfoFull($pathInfo['targetID']);
$userSafeSpace = _get($userInfo,'metaInfo.pathSafeFolder');
if(!$userSafeSpace){return;}
$infoChange = array(
'name' => LNG('explorer.safe.name'),
'icon' => 'user-folder-safe',
'metaInfo' => array('systemSort'=>3000000000,'systemSortHidden'=>true),
'sourceAt' => 'pathSafeSpace',
'ownerUser' => '',
);
$sourceInfo = Model("Source")->pathInfo($userSafeSpace);
if(!$sourceInfo){return;}
// 该用户保险箱根目录;
if($userSafeSpace == $pathInfo['sourceID']){
$userRootName = LNG('common.user').'['.$userInfo['name'].']';
$userRoot = KodIO::make(_get($userInfo,'sourceInfo.sourceID'));
$infoChange['pathAddress'] = array(
array("name"=> $userRootName,"path"=>$userRoot),
array("name"=> LNG('explorer.safe.name'),"path"=>$sourceInfo['path']),
);
$data['current'] = array_merge($data['current'],$infoChange);
return;
}
// 该用户保险箱子目录;
$data['folderList'][] = array_merge($sourceInfo,$infoChange);
}
// 状态及数据处理; isNotOpen/isNotLogin/isLogin;
private function spaceInfo(){
static $result = false;
if(is_array($result)) return $result;
KodUser::checkLogin();
$uesrID = Session::get('kodUser.userID');
$userInfo = Model("User")->getInfoFull($uesrID);
$safeFolder = _get($userInfo,'metaInfo.pathSafeFolder','');
$isLogin = Session::get('pathSafe-userIsLogin') == '1' ? true : false;
$type = !$safeFolder ? 'isNotOpen' : ($isLogin ? 'isLogin' : 'isNotLogin');
$message = array(
'isNotOpen' => LNG('explorer.safe.isNotOpen'),
'isNotLogin' => LNG('explorer.safe.isNotLogin'),
'isLogin' => LNG('explorer.safe.isLogin'),
);
$result = array('type'=>$type,'folder'=>$safeFolder,'message'=>$message[$type]);
$result['folderRoot'] = array(
'name' => LNG('explorer.safe.name'),
'path' => '{block:safe}/',
'type' => 'folder',
'pathDesc' => LNG('explorer.safe.desc'),
'pathSafe' => $type,'pathReadOnly'=>true,
'metaInfo' => array('systemSort'=>3000000000,'systemSortHidden'=>true),
);
if($type != 'isLogin'){
$result['folderRoot']['hasFile'] = false;
$result['folderRoot']['hasFolder'] = false;
}
$result['listEmpty'] = array(
'current' => $result['folderRoot'],
'folderList' => array(),
'fileList' => array(),
'pathSafe' => $type,
'pathSafeMsg' => $result['message'],
'thisPath' => $result['folderRoot']['path'],
);
//trace_log($result);
return $result;
}
// 私密保险箱根目录; 包含功能入口(未开启-提示开启; 登录)
public function listRoot(){
$spaceInfo = $this->spaceInfo();
if($spaceInfo['type'] != 'isLogin'){ // 未登录访问拦截;
return show_json($spaceInfo['listEmpty'],true);
}
// 进入目录;
$folder = '{source:'.$spaceInfo['folder'].'}/';
$listData = Action("explorer.list")->path($folder);
return show_json($listData);
}
// 私密空间功能入口(复用列表接口,不做权限拦截)
public function action(){
$spaceInfo = $this->spaceInfo();
$type = $spaceInfo['type'];
if($this->in['type'] != 'open' && $type == 'isNotOpen'){
return show_json($spaceInfo['listEmpty'],true);
}
$userInfo = Model("User")->getInfoFull(USER_ID);
$userID = $userInfo['userID'];
switch ($this->in['type']){
case 'open':
if(Model("SystemOption")->get('pathSafeSpaceEnable') != '1'){ // 未开启私密保险箱功能;
show_json(LNG('explorer.safe.isNotOpen').' [admin]',false);
}
if($type != 'isNotOpen'){show_json(LNG('explorer.safe.doOpenOpend'),false);}
if(!$userInfo['email']){show_json(LNG('explorer.safe.doOpenTips'),false);}
$password = Input::get('password','require');
Model("Source")->userPathSafeAdd($userID);
Model("User")->metaSet($userID,'pathSafePassword',md5($password));
Action('user.index')->refreshUser($userID);
show_json(LNG('explorer.safe.doOpenSuccess'),true);
break;
case 'login':
if($type == 'isLogin'){return show_json(LNG('explorer.success'),true);}
$password = Input::get('password','require');
if(md5($password) != _get($userInfo,'metaInfo.pathSafePassword')){
show_json(LNG('ERROR_USER_PASSWORD_ERROR'),false);
}
Session::set('pathSafe-userIsLogin','1');
show_json(LNG('explorer.safe.doLoginOk'),true);
break;
case 'logout':
if($type != 'isLogin'){show_json(LNG('user.loginFirst'),false);}
Session::remove('pathSafe-userIsLogin');
show_json(LNG('explorer.success'),true);
break;
case 'close': // 关闭私密保险箱; 移动到根目录,清空密码;
if($type != 'isLogin'){return show_json($spaceInfo['listEmpty'],true);}
$userRoot = $userInfo['sourceInfo']['sourceID'];
$safeFolder = _get($userInfo,'metaInfo.pathSafeFolder','');
Model("Source")->where( array("sourceID"=> $safeFolder) )->data(array('fileType'=>''))->save();
Model("Source")->move($safeFolder,$userRoot,REPEAT_RENAME_FOLDER,LNG('explorer.safe.name').'-copy');
Model("Source")->metaSet($safeFolder,'pathSafeFolderUser',null);
Model("User")->metaSet($userID,'pathSafeFolder',null);
Model("User")->metaSet($userID,'pathSafePassword',null);
Session::remove('pathSafe-userIsLogin');
Action('user.index')->refreshUser($userID);
show_json(LNG('explorer.success'),true);
break;
case 'resetPassword':
$data = Input::getArray(array(
'passwordOld' => array('check'=>'require'),
'password' => array('check'=>'require'),
));
$password = Input::getArray('password','require');
if(md5($data['passwordOld']) != _get($userInfo,'metaInfo.pathSafePassword')){
show_json(LNG('user.oldPwdError'),false);
}
Model("User")->metaSet($userID,'pathSafePassword',md5($data['password']));
Session::remove('pathSafe-userIsLogin');
Action('user.index')->refreshUser($userID);
show_json(LNG('explorer.safe.passwordChanged'),true);
break;
case 'findPasswordSendCode':
$cacheKey = 'pathSafe-findPasswordCheckCode_'.$userID;
$checkInfo = Cache::get($cacheKey);
if(is_array($checkInfo) && time() - $checkInfo['time'] < 60){ //一分钟内只发送一次;
$message = LNG('explorer.safe.sendMailTips').clear_html($userInfo['email'])."<br/>".LNG('explorer.safe.sendMailGet');
show_json($message."<br/>".LNG('explorer.safe.doCheckLimit'),true);
}
$checkInfo = array('code'=> rand_string(6,1),'time'=>time(),'use'=>0);
Cache::set($cacheKey,$checkInfo,3600);
$this->sendCheckCode($checkInfo['code']);
show_json(LNG('explorer.success'),true);
break;
case 'findPasswordReset':
$cacheKey = 'pathSafe-findPasswordCheckCode_'.$userID;
$checkInfo = Cache::get($cacheKey);
if(!is_array($checkInfo) || time() - $checkInfo['time'] > 60*60){ // 1小时过期
Session::remove('pathSafe-findPasswordCheckCode');
show_json(LNG('user.codeExpired'),false);
}
$data = Input::getArray(array(
'checkCode' => array('check'=>'require'),
'password' => array('check'=>'require'),
));
if($data['checkCode'] != $checkInfo['code']){
$checkInfo['use'] += 1;
if($checkInfo['use'] > 5){
Cache::remove($cacheKey);
show_json(LNG('user.codeErrorTooMany'),false);
}
Cache::set($cacheKey,$checkInfo);
show_json(LNG('user.codeError'),false);
}
Model("User")->metaSet($userID,'pathSafePassword',md5($data['password']));
Action('user.index')->refreshUser($userID);
Cache::remove($cacheKey);
show_json(LNG('explorer.safe.passwordChanged'),true);
break;
default:break;
}
return false;
}
// 找回密码发送验证码;
private function sendCheckCode($code){
$userInfo = Session::get("kodUser");
$title = ' '.LNG('explorer.safe.sendMailTitle');
$email = $userInfo['email'];
$result = Action("user.bind")->sendEmail($email,'pathSafe-findPassword',$title,$code);
if(!$result['code']){show_json($result['data'],false);}
show_json(LNG('explorer.safe.sendMailTips').clear_html($email)."<br/>".LNG('explorer.safe.sendMailGet'),true);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/listSearch.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerListSearch extends Controller{
public function __construct(){
parent::__construct();
$this->model = Model("Source");
}
// {search}/key=val@key2=value2;
public function listSearch($pathInfo){
set_timeout();
if( !Action('user.authRole')->authCanSearch() ){
show_json(LNG('explorer.noPermissionAction'),false);
}
return $this->listSearchPath($pathInfo);
}
public function listSearchPath($pathInfo){
$param = array();$paramIn=array();$sourceInfo= array();
$this->parseParam($pathInfo,$param,$paramIn,$sourceInfo);
if( isset($param['option']) &&
in_array('mutil',$param['option']) &&
is_array($param['wordsMutil']) ){
$list = $this->searchMutil($param);
}else{
$list = $this->searchData($param);
}
// 搜索内容,强制列表显示;
if(in_array('content',$param['option']) && !array_key_exists('listTypeSet',$list)){
$list['listTypeSet'] = 'list';
}
$list['searchParam'] = $paramIn;
$list['searchParent'] = $sourceInfo;
if($param['parentPath']){
$list['searchParent'] = IO::info($param['parentPath']);
}
$this->searchResultCount($list);
return $list;
}
private function searchMutil($param){
$param['words'] = '';
$list = false;
if(count($param['wordsMutil']) > 100){
show_json(LNG('common.numberLimit').'(100)',false);
}
foreach($param['wordsMutil'] as $word){
$param['words'] = $word;
$find = $this->searchData($param);
foreach ($find['fileList'] as &$item){$item['searchWords'] = $word;};unset($item);
foreach ($find['folderList'] as &$item){$item['searchWords'] = $word;};unset($item);
if(!$list) {$list = $find;continue;}
$list['fileList'] = array_merge($list['fileList'],$find['fileList']);
$list['folderList'] = array_merge($list['folderList'],$find['folderList']);
}
// 合并相同的结果;
$list['fileList'] = array_values(array_to_keyvalue($list['fileList'],'path'));
$list['folderList'] = array_values(array_to_keyvalue($list['folderList'],'path'));
$list['pageInfo']['totalNum'] = count($list['fileList']) + count($list['folderList']);
$list['pageInfo']['pageTotal'] = 1;
$list['disableSort'] = 1;
return $list;
}
public function searchData($param){
$path = $param['parentPath'];
$parse = KodIO::parse($path);$parseBefore = $parse;
$io = IO::init($path);
if($io->pathParse['truePath']){ // [内部协作分享+外链分享]-物理路径及io路径;
$path = $io->pathParse['truePath'];
$parse = KodIO::parse($path);
}
if($parse['type'] == KodIO::KOD_SHARE_LINK && !$io->pathParse['truePath']){ // 外链分享-物理路径及io路径;
$param['parentID'] = $io->path;
}
$result = Hook::trigger('explorer.listSearch.searchDataBefore',$param);//调整$param;
if(is_array($result)){$param = $result;}
//本地路径搜索;
$searchContent = $param['words'] && in_array('content',$param['option']);
$listData = array('fileList' => array(),'folderList'=>array());
$fromIO = $path && ( in_array($parse['type'],array('',false,KodIO::KOD_IO)) || $searchContent);
if(is_array($param['fileID'])){$fromIO = false;}
if($fromIO){
unset($param['parentID']);
$listData = $this->searchIO($path,$param);
}else{
if(!$param['parentID']) return $listData;
$listData = $this->model->listSearch($param);
}
$result = Hook::trigger('explorer.listSearch.searchDataAfter',$param,$listData); // 调整结果
if(is_array($result)){$listData = $result;}
// pr($fromIO,$path,$param,$parse,$listData);exit;
$listData = $this->listDataParseShareItem($listData,$parseBefore);
$listData = $this->listDataParseShareLink($listData,$parseBefore);
return $listData;
}
// 内部协作分享搜索
public function listDataParseShareItem($listData,$parseSearch){
if($parseSearch['type'] != KodIO::KOD_SHARE_ITEM) return $listData;
$userShare = Action('explorer.userShare');
$shareInfo = Model("Share")->getInfo($parseSearch['id']);
$pathPre = '{shareItem:';
foreach ($listData as $key => $keyList) {
if($key != 'folderList' && $key != 'fileList' ) continue;
$keyListNew = array();
foreach ($keyList as $source){
$pathStart = substr($source['path'],0,strlen($pathPre));// 已经处理过
if($pathStart == $pathPre){$keyListNew[] = $source;continue;}
$source = $userShare->_shareItemeParse($source,$shareInfo);
if($source){$keyListNew[] = $source;}
};
$listData[$key] = $keyListNew;
}
return $listData;
}
// 外链分享搜索
public function listDataParseShareLink($listData,$parseSearch){
if($parseSearch['type'] != KodIO::KOD_SHARE_LINK) return $listData;
$pathPre = '{shareItemLink:';
foreach ($listData as $key => $keyList) {
if($key != 'folderList' && $key != 'fileList' ) continue;
$keyListNew = array();
foreach ($keyList as $source){
$pathStart = substr($source['path'],0,strlen($pathPre));// 已经处理过
if($pathStart == $pathPre){$keyListNew[] = $source;continue;}
$source = Action('explorer.share')->shareItemInfo($source);
if($source){$keyListNew[] = $source;}
};
$listData[$key] = $keyListNew;
}
return $listData;
}
private function parseParam($pathInfo,&$param,&$paramIn,&$sourceInfo){
$paramCheck = array(
'parentPath'=> 'require',
'words' => 'require',
'option' => 'require',
'wordsMutil'=> 'require',
"sizeFrom" => 'float',
"sizeTo" => 'float',
"timeFrom" => 'date',
"timeTo" => 'date',
'fileType' => 'require',//folder|ext;
"user" => 'require',
);
$pathInfo['param'] = trim($pathInfo['param'],'/');
$paramIn = $this->parseSearch($pathInfo['param']);
$param = array();
foreach ($paramCheck as $key => $checkType) {
if( !isset($paramIn[$key]) ) continue;
if( !Input::check($paramIn[$key],$checkType) ) continue;
$param[$key] = $paramIn[$key];
if($checkType == 'date'){
$param[$key] = strtotime($paramIn[$key]);
}
//文件处理
if($checkType == 'fileType' && $paramIn[$key] != 'folder'){
$param[$key] = explode(',',$paramIn[$key]);
}
if($key == 'option'){
$param[$key] = array_filter(explode(',',$paramIn[$key]));
}
if($key == 'wordsMutil'){
$param[$key] = str_replace(array("\r","\r\n"), "\n",$paramIn[$key]);
$param[$key] = array_filter(explode("\n",$param[$key]));
$param[$key] = array_unique(array_values($param[$key]));
}
}
if(isset($param['sizeFrom'])) $param['sizeFrom'] = intval($param['sizeFrom']);
if(isset($param['sizeTo'])) $param['sizeTo'] = intval($param['sizeTo']);
if(isset($param['timeFrom'])) $param['timeFrom'] = intval($param['timeFrom']);
if(isset($param['timeTo'])) $param['timeTo'] = intval($param['timeTo']);
if(!is_array($param['option'])){$param['option'] = array();}
$searchPath = $param['parentPath'] ? $param['parentPath'] : MY_HOME;
$param['words'] = trim($param['words'], '/');
$param['parentID'] = $this->searchPathSource($searchPath, $param['option']);
}
public function searchPathSource($path, $option = false){
if(!$path) return false;
$path = trim($path,'/');
$parse = KodIO::parse($path);
// 权限检测; 搜索内容->view;搜索名称->show
$action = 'view';
if (is_array($option)) {
$action = in_array('content', $option) ? 'view' : 'show';
}
Action('explorer.auth')->can($path, $action); // canView
if($parse['type'] == KodIO::KOD_SHARE_ITEM){
$shareID = $parse['id'];
$sourceID = trim($parse['param'],'/');
$sourceInfo = Action("explorer.userShare")->sharePathInfo($shareID,$sourceID);
if(!$sourceInfo){
show_json(LNG('explorer.noPermissionAction'),false);
}
}else if($parse['type'] == KodIO::KOD_SOURCE){
$sourceInfo = IO::info($path);
}
return $sourceInfo ? $sourceInfo['sourceID'] : false;
}
/**
* 本地路径,IO路径搜索;
*/
public function searchIO($path,$param){
$list = IO::listAll($path);
$fileType = isset($param['fileType']) ? $param['fileType']:'';// folder|allFile|''|ext1,ext2
$onlyFolder = $fileType == 'folder'; // 仅文件夹
$onlyFile = $fileType == 'allFile'; // 仅文件
$allowExt = false;
$searchContent = $param['words'] && in_array('content',$param['option']);
if($fileType && $fileType != 'folder' && $fileType != 'allFile'){
$allowExt = explode(',',strtolower($fileType));
$onlyFile = true;
}
$isLocalFile = file_exists($path);
$result = array('folderList'=> array(),'fileList'=> array());
$matchMax = 20000; $findNum = 0;
foreach($list as $item){
check_abort_echo();
$isFolder = $item['folder'];
if($onlyFolder && !$isFolder) continue;
if($onlyFile && $isFolder) continue;
if($searchContent && $isFolder) continue;
$name = get_path_this($item['path']);
$ext = get_path_ext($name);
if(!$isFolder && $allowExt && !in_array($ext,$allowExt)) continue;
//搜索文件名;
if (isset($param['words']) && $param['words'] &&
!in_array('content',$param['option']) &&
!$this->matchWords($name,$param['words']) ){
continue;
}
if(isset($item['sourceInfo'])){ //IO文件;
$info = $item['sourceInfo'];
}else{
$item['type'] = $item['folder'] ? 'folder':'file';
$item['name'] = $name;$item['ext'] = $ext;$info = $item;
// $info = IO::info($item['path']); // 性能优化,不直接获取;
}
if(!$info) continue;
if( $isFolder && ($param['sizeFrom'] || $param['sizeTo']) ) continue;
$theTime = isset($info['modifyTime']) ? intval($info['modifyTime']):0;//modifyTime createTime;
if( $theTime && isset($param['timeFrom']) &&
$theTime < $param['timeFrom'] ){
continue;
}
if( $theTime && isset($param['timeTo']) &&
$theTime > $param['timeTo'] ){
continue;
}
if( isset($param['sizeFrom']) && !$isFolder &&
intval($info['size']) < $param['sizeFrom'] ){
continue;
}
if( isset($param['sizeTo']) && !$isFolder &&
intval($info['size']) > $param['sizeTo'] ){
continue;
}
if( isset($param['user']) &&
( (is_array($info['modifyUser']) && $param['user'] != $info['modifyUser']['userID']) ||
(is_array($info['createUser']) && $param['user'] != $info['createUser']['userID']) ) ){
continue;
}
if (isset($param['words']) && $param['words'] &&
in_array('content',$param['option']) ){
if(!$this->searchFile($info,$param['words'],$isLocalFile)){
continue; // 内容匹配;
}
}
$findNum ++;
if($findNum > $matchMax) break;
if(kodIO::pathDriverLocal($info['path'])){
$infoFile = IO::info($item['path']); // 物理路径获取权限等情况;
$infoFile = is_array($infoFile) ? $infoFile:array();
$info = array_merge($infoFile,$info);
}
$typeKey = $isFolder ? 'folderList':'fileList';
$result[$typeKey][] = $info;
}
// pr($path,$param,$list,$result,$allowExt);exit;
return $result;
}
private function searchFile(&$file,$search,$isLocalFile){
if($file['size'] <= 3) return false;
if(is_text_file($file['ext']) && $isLocalFile ){
if($file['size'] >= 1024*1024*10) return false;
$content = IO::getContent($file['path']);
}else{
$content = Hook::trigger('explorer.listSearch.fileContentText',$file);
if(!$content && is_text_file($file['ext'])){
if($file['size'] >= 1024*1024*10) return false;
$content = IO::getContent($file['path']);
}
}
if(!$content) return false;
if(!is_text_file($file['ext'])){//单行数据展示
$find = $this->contentSearchMatch($content,$search);
if($find){$file['searchContentMatch'] = $find;}
return $find ? true : false;
}
$find = content_search($content,$search,false,505);
if($find){$file['searchTextFile'] = $find;}
return $find ? true : false;
}
// $content中匹配到$word的内容截取; 最大长度默认300; 前一行+
public function contentSearchMatch(&$content,$word,$maxContent = 300){
if(!$content || !$word) return false;
$pose = stripos($content,$word);
if($pose === false) return false;
$start = intval($pose) <= 0 ? 0 : $pose;
$stopChar = array("\n",' ',',','.','!','.','!',';');
for($i = $start; $i >= 0; $i--){
$start = $i;
if($pose - $i > $maxContent * 0.2 - strlen($word)){break;}
if(in_array($content[$i],$stopChar)) break;
}
$start = $start <= 20 ? 0 : $start;
$length = strlen($word) + $maxContent;
$str = utf8Repair(substr($content,$start,$length));
if(strlen($content) > $start + $length + 10){$str .= '...';}
$str = str_replace(array("\n\n",' ','"'),array("\n",' ','"'),$str);
// pr($word,$pose,$start,$length,$str,$content);exit;
return $str;
}
// 多个搜索词并列搜索; "且"语法,返回同时包含的内容;
private function matchWords($name,$search){
$wordsArr = explode(' ',trim($search));
$result = true;
if( strlen($search) > 2 &&
(substr($search,0,1) == '"' && substr($search,-1) == '"') ||
(substr($search,0,1) == "'" && substr($search,-1) == "'")
){
$search = substr($search,1,-1);
$wordsArr = array($search);
}
foreach($wordsArr as $searchWord){
$searchWord = trim($searchWord);
if(!$searchWord) continue;
if(stripos($name,$searchWord) === false){
$result = false;
break;
}
}
return $result;
}
private function searchResultCount(&$list){
if(!$list['searchParam']['words']) return;
$list['searchCount'] = 0;
foreach ($list['fileList'] as $item) {
if(!is_array($item['searchTextFile'])) continue;
$list['searchCount'] += count($item['searchTextFile']);
}
}
public function parseSearch($param){
if(!$param) return array();
$param = ltrim($param,'/');
$all = explode('@',$param);
$result = array();
foreach ($all as $item) {
if(!$item || !strstr($item,'=')) continue;
$keyv = explode('=',$item);
if(count($keyv) != 2 || !$keyv[0] || !$keyv[1]) continue;
$value = trim(rawurldecode($keyv[1]));
if(strlen($value) > 0 ){
$result[$keyv[0]] = $value;
}
}
return $result;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/listView.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 文件夹首选项(显示模式,排序方式)
* 跟随文件夹,前端可切换,切换后保持到当前路径配置;并且设置为全局默认值; 保留最近200条记录;
* 优先级: 指定自己 > 指定最近上级 > 默认
* -----------------------------------
* listType // list|icon|split 指定显示模式;
* listSortField // name|type|size|modifyTime 指定排序字段;
* listSortOrder // up|down 指定排序方式
* listIconSize // number listType为icon图标模式时图标大小;
*
* 其他文件夹列表接口字段扩展;
* -----------------------------------
* listTypeSet // list|icon|split 强制指定显示模式; 指定后前端不再能切换显示模式;
* pageSizeArray // [100,200,500,1000,2000,5000] 后端指定分页方式;
* disableSort // 0|1 禁用排序;
* listTypePhoto // 0|1 强制相册模式展示;
*/
class explorerListView extends Controller{
public function __construct(){
parent::__construct();
$this->model = Model("Source");
}
// 数据处理;
public function listDataSet(&$data){
if(!$data || !is_array($data['current'])) return;
if(isset($data['listTypeSet'])) return;
$listTypeAllow = Model("UserOption")->get('listTypeKeep') != '0';
$listSortAllow = Model("UserOption")->get('listSortKeep') != '0';
if(!$listTypeAllow && !$listSortAllow) return;
$findPath = $this->makePathParents($data['current']);
if($listTypeAllow){$this->listDataSetListType($findPath,$data);}
if($listSortAllow){$this->listDataSetListSort($findPath,$data);}
}
private function listDataSetListType($findPath,&$data){
$dataListType = $this->dataGetListType();
$listType = '';$listIconSize = '';
foreach($findPath as $thePath){
if(!isset($dataListType[$thePath])) continue;
$listType = $dataListType[$thePath];break;
}
$listTypeInfo = explode(':',$listType);
$listType = $listTypeInfo[0];
if(count($listTypeInfo) == 2 && $listTypeInfo[0] == 'icon'){
$listIconSize = $listTypeInfo[1];
}
if($listType){$data['listType'] = $listType;}
if($listIconSize){$data['listIconSize'] = $listIconSize;}
}
private function listDataSetListSort($findPath,&$data){
$dataListSort = $this->dataGetSort();
$sortBy = '';$sortField = '';$sortOrder = '';
foreach($findPath as $thePath){
if(!isset($dataListSort[$thePath])) continue;
$sortBy = $dataListSort[$thePath];break;
}
$sortByInfo = explode(':',$sortBy);
if(count($sortByInfo) == 2){
$sortField = $sortByInfo[0];
$sortOrder = $sortByInfo[1];
}
if($sortField){$data['listSortField'] = $sortField;}
if($sortOrder){$data['listSortOrder'] = $sortOrder;}
}
// 获取目录所有上级目录;
private function makePathParents($pathInfo){
$parents = array();
if(_get($pathInfo,'sourceID')){
if(!_get($pathInfo,'parentLevel')){
$sourceInfo = Model('Source')->sourceInfo($pathInfo['sourceID']);
$pathInfo['parentLevel'] = $sourceInfo ? $sourceInfo['parentLevel'] : '';
}
$parents = Model("Source")->parentLevelArray($pathInfo['parentLevel']);
$parents[] = $pathInfo['sourceID'];
}else{
$last = '';
$pathArr = explode('/', rtrim($pathInfo['path'],'/'));
for ($i = 0; $i < count($pathArr); $i++){
$last = $last.$pathArr[$i].'/';
$parents[] = $last;
}
}
return array_reverse($parents);
}
private function dataGetListType(){
$data = Model("UserOption")->get('listType','folderInfo',true);
return is_array($data) ? $data : array();
}
private function dataGetSort(){
$data = Model("UserOption")->get('listSort','folderInfo',true);
return is_array($data) ? $data : array();
}
public function dataSave($param){
$listType = Input::get('listViewKey','in',null,array('listType','listSort'));
$value = Input::get('listViewValue','require');
$path = Input::get('listViewPath','require');
// 清空数据;
if(isset($param['clearListView']) && $param['clearListView'] == '1'){
Model("UserOption")->remove('listType','folderInfo');
Model("UserOption")->remove('listSort','folderInfo');
return;
}
$listTypeAllow = Model("UserOption")->get('listTypeKeep') != '0';
$listSortAllow = Model("UserOption")->get('listSortKeep') != '0';
if(!$listTypeAllow && $listType == 'listType') return;
if(!$listSortAllow && $listType == 'listSort') return;
$numberMax = 200;
$listData = Model("UserOption")->get($listType,'folderInfo',true);
$storePath = $this->parseStorePath($path).'';
if(!is_array($listData)){$listData = array();}
if(isset($listData[$storePath])){unset($listData[$storePath]);}
if(count($listData) >= $numberMax){
$listData = array_slice($listData,count($listData) - $numberMax + 1,$numberMax - 1,true);
}
// trace_log(array($path,$storePath,$value));
$listData[$storePath] = $value;
Model("UserOption")->set($listType,$listData,'folderInfo');
}
private function parseStorePath($path){
$pathParse = KodIO::parse($path);
$thePath = rtrim($path,'/').'/';
if($pathParse['type'] == '') return $thePath;
if($pathParse['type'] == KodIO::KOD_SOURCE) return $pathParse['id'];
if($pathParse['type'] == KodIO::KOD_SHARE_ITEM){
$shareInfo = Model('Share')->getInfo($pathParse['id']);
if($shareInfo && $shareInfo['sourceID'] != '0') return trim($pathParse['param'],'/');
}
return $thePath;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/publish.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
// 文件发布: 首先复制到系统临时目录,并开放该目录给指定用户可见; 发布:从临时目录复制到发布目录;
class explorerPublish extends Controller{
function __construct(){
parent::__construct();
}
// 构造发布临时目录并生成访问路径;
public function makeTemp($fromPath,$publishPath,$userAuth){
$fromPathInfo = IO::info($fromPath);
$destPathInfo = IO::info($publishPath);
if(!$fromPathInfo || !$destPathInfo || $destPathInfo['type'] != 'folder' ) return;
$systemPublish = KodIO::systemPath('systemPublish');
$tempPath = IO::copy($fromPath,$systemPublish);
$tempPathInfo = IO::info($tempPath);
if(!$tempPathInfo) return;
$publishData = array(
'fromPath' => $fromPath,
'publishPath' => $publishPath,
'time' => time(),
);
$publishData = json_encode($publishData);
Model('Source')->metaSet($tempPathInfo['sourceID'],'publishData',$publishData);
$viewPath = $this->makeShare($tempPath,$userAuth);
return array('tempPath'=>$tempPath,'viewPath'=>$viewPath);
}
// 取消临时文件(夹)
public function cancle($tempPath){
$pathInfo = IO::info($tempPath);
if(!$tempPath || !$pathInfo || !$pathInfo['sourceID']) return;
$this->removeShare($tempPath);
IO::remove($tempPath);
}
// 发布
public function finished($tempPath){
$pathInfo = IO::info($tempPath);
$publishData = _get($pathInfo,'metaInfo.publishData');
if(!$tempPath || !$publishData) return;
$publishData = json_decode($publishData,true);
if(!$publishData || !IO::info($publishData['publishPath'])) return false;
IO::copy($tempPath,$publishData['publishPath']);
$this->cancle($tempPath);
}
/**
* 构建临时访问路径;
* authTo: [{"targetType":"1","targetID":"23","authID":"1"},...]
*/
private function makeShare($tempPath,$userAuth){
$pathInfo = IO::info($tempPath);
$authTo = array();
foreach ($userAuth as $userID=>$authID){
if(!$userID || !$authID) continue;
$authTo[] = array("targetType"=>SourceModel::TYPE_USER, 'targetID'=>$userID,"authID"=>$authID);
}
if(!$authTo || !$pathInfo) return false;
$data = array('isShareTo' => 1,'authTo'=> $authTo);
$shareID = Model('Share')->shareAdd($pathInfo['sourceID'],$data);
return KodIO::makePath(KodIO::KOD_SHARE_ITEM,$shareID,$pathInfo['sourceID']);
}
private function removeShare($tempPath){
$pathInfo = IO::info($tempPath);
$shareID = $pathInfo['sourceInfo']['shareInfo']['shareID'];
if(!$shareID) return;
Model('Share')->remove(array($shareID));
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/recycleDriver.class.php'
<?php
/**
* 物理文件夹删除;
* 回收站支持处理;
*/
class explorerRecycleDriver extends Controller{
public function __construct(){
parent::__construct();
}
public function removeCheck($path,$toRecycle=true){
$path = KodIO::clear($path);
$pathParse = KodIO::parse($path);
$driver = IO::init($path);
if(!$toRecycle || $pathParse['type'] == KodIO::KOD_SOURCE){
return IO::remove($path,$toRecycle);
}
$recycleLocal = rtrim(DATA_PATH,'/').'/'.$this->localRecycleFolder().'/';
$recyclePath = rtrim($pathParse['pathBase'],'/').'/.recycle/';
if(!$pathParse['type']){$recyclePath = $recycleLocal;}
// 协作分享内容: 某人删除时, 移动到自己的回收站(物理路径及io路径; db路径处理)
if($pathParse['type'] == KodIO::KOD_SHARE_ITEM && $driver->getType() == 'dbshareitem'){
$recyclePath = rtrim($driver->getPathRoot(),'/').'/.recycle/';
}
return $this->moveToRecycle($path,$recyclePath,IO::pathFather($path));
}
/**
* 追加物理路径
*/
public function appendList(&$data,$pathParse){
if($pathParse['type'] != KodIO::KOD_USER_RECYCLE) return;
$list = $this->listData();
$listNew = $list;
foreach ($list as $toPath => $fromPath){
$parse = KodIO::parse($toPath);
if($parse['driverType'] == 'io') {
$info = Model('Storage')->driverInfo($parse['id']);
if(!$info) {
unset($listNew[$toPath]);
continue;
}
}
$ioType = IO::getType($toPath);
$allowInfo = $ioType == 'local' || $ioType == 'dbshareitem'; // 仅允许本地存储属性访问; 访问速度优化处理;
if(!$allowInfo){
$name = get_path_this($toPath);
$info = array(
'path' => rtrim($fromPath,'/').'/'.$name,
'name' => $name,
'type' => preg_match("/.+\.[a-zA-Z0-9]{1,6}$/",$name,$match) ? 'file' : 'folder',
'size' => '-1',
);
if($info['type'] == 'folder'){
$data['folderList'][] = $info;
}else{
$data['fileList'][] = $info;
}
continue;
}
// $pathParse['type'];local;miniIO; info; 网络存储则不获取属性;
$info = IO::info($toPath);
if(!$info){
unset($listNew[$toPath]);
continue;
}
// 协作分享,删除到回收站的内容; 有权限时数据会重复/去重处理;
if($info['sourceID']){
foreach($data['fileList'] as $i=>$item) {
if($info['sourceID'] == $item['sourceID']){unset($data['fileList'][$i]);}
}
foreach($data['folderList'] as $index=>$item) {
if($info['sourceID'] == $item['sourceID']){unset($data['folderList'][$i]);}
}
}
$info['path'] = rtrim($fromPath,'/').'/'.$info['name'];
if($parse['type'] == KodIO::KOD_SHARE_ITEM){$info['path'] = $toPath;}
if($info['type'] == 'folder'){
$data['folderList'][] = $info;
}else{
$data['fileList'][] = $info;
}
}
// 有不存在内容则自动清除;
if(count($listNew) != count($list)){
$this->resetList($listNew);
}
$data['folderList'] = array_values($data['folderList']);
$data['fileList'] = array_values($data['fileList']);
// pr($data);exit;
}
// 彻底删除;
public function remove($sourceArr){
$list = $this->listData();
$listNew = $list;
foreach ($list as $toPath => $fromPath){
// 删除所有, 或者当前在待删除列表中则删除该项;
$beforePath = rtrim($fromPath,'/').'/'.get_path_this($toPath);
if(!$sourceArr ||
in_array($beforePath,$sourceArr) ||
in_array(trim($beforePath,'/').'/',$sourceArr)
){
IO::remove($toPath,false);
unset($listNew[$toPath]);
}
}
if(count($listNew) != count($list)){
$this->resetList($listNew);
}
}
// 还原
public function restore($sourceArr){
$list = $this->listData();
$listNew = $list;
foreach($list as $thePath => $beforePath){
IO::move($thePath,$beforePath,REPEAT_RENAME_FOLDER);
unset($listNew[$thePath]);
}
if(count($listNew) != count($list)){
$this->resetList($listNew);
}
}
/**
* 删除到回收站;
* 物理路径: 移动到 TEMP_PATH/.recycle/[user_id]
* io路径 : 移动到该io/.recycle 下;
*/
private function moveToRecycle($path,$recyclePath,$beforePath){
if(substr($path,0,strlen($recyclePath)) == $recyclePath){
return IO::remove($path,false);//已经在回收站中,则不再处理;
}
$destPath = IO::mkdir($recyclePath);
$destInfo = $destPath ? IO::info($destPath):false;
if(!$destInfo){return $path;} //新建失败则返回;
if(IO::isParentOf($destPath,$path)){return IO::remove($path,false);} // 已经在回收站中则直接删除;
$toPath = IO::move($path,$destPath,REPEAT_RENAME_FOLDER);
$list = $this->listData();
$list[$toPath] = $beforePath;
$this->resetList($list);
return $toPath;
}
private function listData(){
$this->localRecycleFolder();
$list = Model("UserOption")->get('recycleList','recycle');
return $list ? json_decode($list,true):array();
}
private function resetList($list){
$listData = json_encode($list);
// options表key=>value value最长长度限制;
if(strlen($listData) > 65536){
show_json(LNG('explorer.recycleClearForce'),false);
}
Model("UserOption")->set('recycleList',$listData,'recycle');
}
// 物理路径回收站文件名处理(安全优化, 隐藏文件夹名,避免被遍历)
private function localRecycleFolder(){
// Model("SystemOption")->set('recycleFolder','');return '.recycle';//debug;
$recycleFolder = Model("SystemOption")->get('recycleFolder');
if($recycleFolder) return $recycleFolder;
$recycleFolder = '.recycle_'.rand_string(8);
$recycleLocal = DATA_PATH.$recycleFolder.'/';
// =====1.35前版本兼容处理;====
$recycleBefore= DATA_PATH.'.recycle/';
$list = Model("UserOption")->get('recycleList','recycle');
$list = $list ? json_decode($list,true):array();
$listNew = array();
foreach ($list as $path => $beforeAt){
$newPath = $path;
if(substr($path,0,strlen($recycleBefore)) == $recycleBefore){
$newPath = $recycleLocal.substr($path,strlen($recycleBefore));
}
$listNew[$newPath] = $beforeAt;
}
Model("UserOption")->set('recycleList',json_encode($listNew),'recycle');
@rename($recycleBefore,get_path_father($recycleBefore).'/'.$recycleFolder);
// =====兼容end====
IO::mkdir($recycleLocal);
file_put_contents($recycleLocal.'index.html','');
Model("SystemOption")->set('recycleFolder',$recycleFolder);
return $recycleFolder;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/seo.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 搜索引擎优化;
*/
class explorerSeo extends Controller{
function __construct(){
parent::__construct();
}
public function check(){
I18n::set('title','');
Hook::bind('templateCommonFooter','explorer.seo.makeFooter');
if(MOD == 'sitemap'){$this->siteMap();}
if(MOD == 's'){$this->shareView(ST);}
}
public function makeFooter(){
$powerBy = LNG("common.copyright.powerBy");
$homePage = str_replace('%s',APP_HOST,LNG('common.copyright.homepage'));
$isKeep = _get($this->in,'keep') == '1' ? 'keep=1':null;
$siteMap = urlApi('sitemap',$isKeep);
$link = 'https://github.com/kalcaddle/kodbox';
$html = "<div class='page-footer' style='display:none;'>\n\t";
$html .= "<h3>{$powerBy} <a href='{$link}' target='_blank'>V".KOD_VERSION."</a></h3>\n\t";
$html .= "<h3>{$homePage}</h3>\n\t";
$html .= "<h3><a href='".$siteMap."'>Files</a></h3></div>\n\t";
echo $html;
}
/**
* 搜索引擎抓取:
* 1. 外链分享列表;分页处理;
* 2. 外链分享文件概览,文件夹子文件 (文本文件内容截取10k);
* 3. 外链分享文件夹列表;
*/
public function siteMap(){
if($this->config['settings']['allowSEO'] != 1){ // keep=1
header('HTTP/1.1 404 Not Found');
return show_tips("Not allow robots!");
}
if(!defined("USER_ID")){define("USER_ID",0);}
switch(ST){
case 'index': $this->shareList();exit;break;
case 'share': $this->shareView(ACT);exit;break;
case 'file' : $this->shareFileOut();exit;break;
default: break;
}
}
private function displayContent($html,$link=''){
if(!$html) return;
$link = $link ? $link : APP_HOST;
$location = '<script type="text/javascript">window.location.href="'.$link.'"</script>';
$GLOBALS['templateContent'] = "<div class='page-view-search'>{$html}</div>";
if(_get($this->in,'keep') != '1'){
// pr_trace($link);exit;
$GLOBALS['templateContent'] =$location.$GLOBALS['templateContent'];
}
Hook::bind('templateCommonContent','explorerSeo.echoContent');
include(TEMPLATE.'user/index.html');
}
private function displayError($content,$link=''){
header('HTTP/1.1 404 Not Found');
$html = '<div class="info-alert info-alert-red"><p>'.$content.'</p></div>';
$this->displayContent($html,$link);
}
public function echoContent(){
echo "<style>
body{
position:relative !important;width:auto;height:auto;
background:#f0f2f5;overflow:auto !important;
}
.page-footer{display:block !important;text-align: center;color:#aaa;}
.page-footer h3{display:inline-block;font-size: 13px;font-weight:400;}
</style>";
echo $GLOBALS['templateContent'];
}
// 分享列表;
private function shareList(){
$title = LNG('explorer.share.linkTo');
I18n::set('title',$title.' - ');
$model = Model('Share');
$where = array(
'isLink' => '1',
'password' => '',
'timeTo' => array('<',time())
);
$this->in['pageNum'] = 15;//>5;
$this->in['page'] = _get($this->in,'page','1');
$list = $model->where($where)->order("createTime desc")->selectPage();
$listHtml = '';
$isKeep = _get($this->in,'keep') == '1' ? 'keep=1':null;
$siteMap = urlApi('sitemap/',$isKeep);
$pageHtml = $this->makePage($list['pageInfo'],$siteMap,5);
$list = Model('Share')->listDataApply($list['list']);
foreach ($list as $item){
$listHtml .= $this->shareMakeItem($item);
}
if(!$list){
$listHtml = "<div class='grey-6 align-center mt-30'>".LNG('common.empty')."</div>";
}else{
$listHtml = "
<li class='file-item header'>
<span class='title-item item-name'>".LNG('common.name')."</span>
<span class='title-item item-user'>".LNG('explorer.auth.share')."</span>
<span class='title-item item-size'>".LNG('explorer.file.size')."</span>
<span class='title-item item-time'>".LNG('explorer.file.shareTime')."</span>
</li>".$listHtml;
}
$html = "<h3>{$title}</h3><ul class='list-file list-file-share'>$listHtml</ul>$pageHtml";
$this->displayContent($html);
}
/**
* 分享内容: 分享文件;分享文件夹;分享文件夹子文件
* 分享信息: 分享信息,路径信息,文件; 文件夹--列表
* 文件展示: 文本-展示1M; 图片展示img; 其他文件:下载链接; (有预览权限)
*/
private function shareView($hash){
$viewPath = trim(_get($this->in,'view',''),'/');
$view = $viewPath ? '&view='.rawurlencode($viewPath):'';
$linkTrue = APP_HOST.'#s/'.$hash.str_replace('%2F','/',$view);
$shareInfo = Model('Share')->getInfoByHash($hash);
$error = $this->shareCheck($shareInfo);
if($error) return $this->displayError($error,$linkTrue);
$sourcePath = $shareInfo['sourcePath'].'/'.$viewPath;
$shareDesc = $this->shareMakeItem($shareInfo);
$linkPage = $this->shareLink($shareInfo);
$addressHtml = "<a href='{$linkPage}'>{$shareInfo['title']}</a>";
$viewPathArr = explode('/',$viewPath);
for($i = 0; $i < count($viewPathArr); $i++){
if(!$viewPathArr[$i]) continue;
$viewPathNow = implode('/',array_slice($viewPathArr,0,$i+1));
$link = $this->shareLink($shareInfo,$viewPathNow);
$addressHtml .= " / <a href='{$link}'>".htmlentities($viewPathArr[$i])."</a>";
}
$html = "
<div class='share-header-info'>{$shareDesc}</div>
<div class='address-info'>".LNG('common.position').": ".$addressHtml."</div>";
$pathInfo = IO::infoFull($sourcePath);
if(!$pathInfo) return $this->displayError(LNG('common.pathNotExists'),$linkTrue);
// 标题处理;
$currentName = $viewPath ? $pathInfo['name'].' - ' : '';
I18n::set('title',$currentName.$shareInfo['title'].' - ');
if($pathInfo['type'] == 'file'){
$movieFile = explode(',','mov,mp4,webm,m4v,mkv');
$imageFile = explode(',','jpg,jpeg,png,bmp,ico,gif,webp');
$linkFile = $this->shareLink($shareInfo,$viewPath,'file');
if(is_text_file($pathInfo['ext'])){
$content = IO::fileSubstr($pathInfo['path'],0,1024*500);
$html .= "<p><pre class='the-code'><code>".htmlentities($content)."</code></pre></p>";
$html .= "<script src='".STATIC_PATH."app/vender/markdown/highlight.min.js'></script>
<script>hljs.initHighlightingOnLoad();</script>";
}else if(in_array($pathInfo['ext'],$imageFile)){
$html .= "<p class='content-file'><img src='{$linkFile}' /></p>";
}else if(in_array($pathInfo['ext'],$movieFile)){
$html .= "<video class='content-file' src='{$linkFile}' controls='controls'></video>";
}else{
$html .= "
<div class='content-download'>
<a class='kui-btn kui-btn-blue' href='{$linkFile}'
target='_blank'>".LNG('common.download')."</a>
<div class='grey-6'>".LNG('explorer.share.errorShowTips')."</div>
</div>";
}
}else{
$html .= $this->shareViewFolder($shareInfo,$pathInfo);
}
$this->displayContent($html,$linkTrue);
}
private function shareFileOut(){
$shareInfo= Model('Share')->getInfoByHash(ACT);
$error = $this->shareCheck($shareInfo);
if($error) return $this->displayError($error);
$viewPath = trim(_get($this->in,'view',''),'/');
$sourcePath = $shareInfo['sourcePath'].'/'.$viewPath;
$pathInfo = IO::infoFullSimple($sourcePath);
if(!$pathInfo) return $this->displayError(LNG('common.pathNotExists'));
IO::fileOut($pathInfo['path']);exit;
}
private function shareViewFolder($shareInfo,$pathInfo){
$pathPre = _get($shareInfo['sourceInfo'],'pathDisplay',$shareInfo['sourceInfo']['path']);
$list = IO::listPath($pathInfo['path']);
$fileList = KodSort::arraySort($list['fileList'],'name');
$folderList = KodSort::arraySort($list['folderList'],'name');
$listAll = array_merge($folderList,$fileList);
$listAll = array_slice($listAll,0,2000);
$listHtml = '';
foreach ($listAll as $pathInfo){
$pathDisplay = _get($pathInfo,'pathDisplay',$pathInfo['path']);
if(substr($pathDisplay,0,strlen($pathPre)) != $pathPre) continue;
$viewPath = substr($pathDisplay,strlen($pathPre));
$link = $this->shareLink($shareInfo,$viewPath);
$time = date('Y-m-d H:i',$pathInfo['createTime']);
$size = size_format($pathInfo['size']);
$size = $pathInfo['type'] != 'folder' || $pathInfo['size'] ? $size:'';
$ext = $pathInfo['type'] == 'folder' ? 'folder' : $pathInfo['ext'];
$listHtml .= "
<li class='file-item {$pathInfo['type']}'>
<a class='file-link' href='{$link}'></a>
<span class='title-item item-name'>
<i class='path-ico'><i class='x-item-icon x-{$ext} small'></i></i>
<a href='{$link}'>".htmlentities($pathInfo['name'])."</a>
</span>
<span class='title-item item-size'>{$size}</span>
<span class='title-item item-time'>{$time}</span>
</li>";
}
if(!$listAll){
$listHtml = "<div class='grey-6 align-center mt-30'>".LNG('common.empty')."</div>";
}else{
$listHtml = "
<li class='file-item header'>
<span class='title-item item-name'>".LNG('common.name')."</span>
<span class='title-item item-size'>".LNG('explorer.file.size')."</span>
<span class='title-item item-time'>".LNG('common.createTime')."</span>
</li>".$listHtml;
}
return "\n<ul class='list-file list-file-folder'>".$listHtml."</ul>\n";
}
private function shareLink($shareInfo,$viewPath='',$page='share'){
$view = $viewPath ? '&view='.rawurlencode($viewPath):'';
$view = str_replace('%2F','/',$view);
$keep = _get($this->in,'keep') == '1' ? '&keep=1' : '';
return urlApi('sitemap/'.$page.'/'.$shareInfo['shareHash'],ltrim($keep.$view,'&'));
}
// 分享权限处理;
private function shareCheck($shareInfo){
$msg = array(
'notExists' => LNG('explorer.share.notExist'),
'needPassword' => LNG('explorer.share.needPwd'),
'onlyLogin' => LNG('explorer.share.onlyLogin'),
'timeout' => LNG('explorer.share.errorTime'),
'notDownload' => LNG('explorer.share.noDownTips'),
'downloadLimit' => LNG('explorer.share.downExceedTips'),
);
if(!$shareInfo || !is_array($shareInfo)) return $msg['notExists'];
$downloadNumber = _get($shareInfo,'options.downloadNumber');
$downloadLimit = $downloadNumber && intval($downloadNumber) > intval($shareInfo['numDownload']);
if($shareInfo['timeTo'] && intval($shareInfo['timeTo']) < time()) return $msg['timeout'];
if($shareInfo['password']) return $msg["needPassword"];
if(_get($shareInfo,'options.notDownload') == '1') return $msg['notDownload'];
if(_get($shareInfo,'options.onlyLogin') == '1') return $msg['onlyLogin'];
if($downloadLimit) return $msg['downloadLimit'];
return false;
}
private function shareMakeItem($item){
if($this->shareCheck($item)) return '';
$pathInfo = $item['sourceInfo'];
if(!$item['userInfo']){
$userList = Model('User')->userListInfo(array($item['userID']));
$item['userInfo'] = $userList[$item['userID']];
}
if(!$pathInfo && $item['sourceID'] == '0'){
$pathInfo = IO::info($item['sourcePath']);
}
if(!$pathInfo) return '';
$link = $this->shareLink($item);
$user = $item['nickName'] ? $item['nickName']:$item['name'];
$time = date('Y-m-d H:i',$item['createTime']);
$size = size_format($pathInfo['size']);
$size = $pathInfo['type'] != 'folder' || $pathInfo['size'] ? $size:'';
$ext = $pathInfo['type'] == 'folder' ? 'folder' : $pathInfo['ext'];
return "
<li class='file-item'>
<a class='file-link' href='{$link}'></a>
<span class='title-item item-name'>
<i class='path-ico'><i class='x-item-icon x-{$ext} small'></i></i>
<a href='{$link}'>".htmlentities($item['title'])."</a>
</span>
<span class='title-item item-user'>".htmlentities($user)."</span>
<span class='title-item item-size'>{$size}</span>
<span class='title-item item-time'>{$time}</span>
</li>";
}
private function makePage($info,$linkPre,$showNum=5){
if($showNum <= 2 || !$info || $info['pageTotal'] == 0 ) return '';
$total = $info['pageTotal'];
$pageDesc =
"<span class='page-info-text'>
{$total}".LNG('explorer.table.page')." <span class='grey-6'>
({$info['totalNum']}".LNG('explorer.table.items').")</span>
</span>";
if($total <= 1) return "<div class='page-box'>\n{$pageDesc}</div>";
$from = $info['page'] - intval(($showNum - 1) / 2);
$to = $info['page'] + intval(($showNum - 1) / 2) + ($showNum % 2 == 0 ? 1 : 0);
$from = $to > $total ? ($total - $showNum + 1) : $from;
$to = $from < 1 ? $showNum : $to;
$from = $from <= 1 ? 1 : $from;
$to = $to >= $total ? $total : $to;
$html = '';
for($i = $from; $i<=$to; $i++){
if($i == $info['page']){
$html .= "<a href='{$linkPre}&page={$i}' class='current'>{$i}</a>\n";
}else{
$html .= "<a href='{$linkPre}&page={$i}'>{$i}</a>\n";
}
}
if($total > $showNum){
$html = "<a href='{$linkPre}&page=1' class='page-first'>".LNG('explorer.table.first')."</a>\n".$html;
$html.= "<a href='{$linkPre}&page={$total}' class='page-last'>".LNG('explorer.table.last')."</a>\n";
}
return "<div class='page-box'>\n{$html}{$pageDesc}\n</div>";
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/share.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerShare extends Controller{
private $model;
function __construct(){
parent::__construct();
$this->model = Model('Share');
$notCheck = array('link','file','pathParse','fileDownloadRemove','unzipListHash','fileGetHash');
// 检测并处理分享信息
if( strtolower(ST) == 'share' && !in_array_not_case(ACT,$notCheck) ){
$shareID = $this->parseShareID();
$this->initShare($shareID);
if(strtolower(MOD.'.'.ST) == 'explorer.share'){$this->authCheck();}
}
}
// 自动解析分享id; 通过path或多选时dataArr;
private function parseShareID(){
$shareID = $this->in['shareID'];
if($shareID) return $shareID;
$thePath = $this->in['path'];
if(!$thePath && isset($this->in['dataArr'])){
$fileList = json_decode($this->in['dataArr'],true);
$thePath = $fileList[0]['path'];
}
$parse = KodIO::parse($thePath);
if($parse['type'] == KodIO::KOD_SHARE_LINK){
$shareID = $parse['id'];
}
return $shareID;
}
// 通用生成外链
public function link($path,$downFilename=''){
if(!$path || !$info = IO::info($path)) return;
$pass = Model('SystemOption')->get('systemPassword');
$hash = Mcrypt::encode($info['path'],$pass);
$addParam = '&name=/'.rawurlencode($info['name']);
if($downFilename){
$addParam = '&downFilename='.rawurlencode($downFilename);
}
return urlApi('explorer/share/file',"hash={$hash}".$addParam);
}
// 构造加密链接,相同文件每次一样,确保浏览器能够缓存;
public function linkFile($file,$addParam=''){
$pass = Model('SystemOption')->get('systemPassword');
$hash = Mcrypt::encode($file,$pass,false,'kodcloud');
return urlApi('explorer/share/file',"hash={$hash}".($addParam ? '&'.$addParam:'') );
}
public function linkSafe($path,$downFilename=''){
if(!KodUser::isLogin()){return $this->link($path,$downFilename);}
if(!$path || !$info = IO::info($path)) return;
$link = Action('user.index')->apiSignMake('explorer/index/fileOut',array('path'=>$path));
$addParam = '&name=/'.rawurlencode($info['name']);
$addParam .= $downFilename ? '&downFilename='.rawurlencode($downFilename):'';
return $link.$addParam;
}
public function linkOut($path,$token=false){
$parse = KodIO::parse($path);
$info = IO::info($path);
$apiKey = 'explorer/index/fileOut';
if($parse['type'] == KodIO::KOD_SHARE_LINK){
$apiKey = 'explorer/share/fileOut';
}
$etag = substr(md5($path),0,5);
$name = isset($this->in['name']) ? rawurlencode($this->in['name']):'';
if($info){
$name = rawurlencode($info['name']);
$etag = substr(md5($info['modifyTime'].$info['size']),0,5);
}
$url = urlApi($apiKey,"path=".rawurlencode($path).'&et='.$etag.'&name=/'.$name);
if($token) $url .= '&accessToken='.Action('user.index')->accessToken();
return $url;
}
public function file(){
if(!$this->in['hash']) return;
$path = $this->fileHash($this->in['hash']);
$isDownload = isset($this->in['download']) && $this->in['download'] == 1;
$downFilename = !empty($this->in['downFilename']) ? $this->in['downFilename'] : false;
Action('explorer.index')->fileOutUpdate($path,$isDownload,$downFilename);
}
// 文件外链解析;
private function fileHash($hash){
if(!$hash || strlen($hash) > 5000) return;
$path = Mcrypt::decode($hash,Model('SystemOption')->get('systemPassword'));
$fileInfo = $path ? IO::info($path) : false;
if(!$fileInfo){show_json(LNG('common.pathNotExists'),false);}
if($fileInfo['isDelete'] == '1'){show_json(LNG('explorer.pathInRecycle'),false);}
return $path;
}
/**
* 其他业务通过分享路径获取文档真实路径; 文件打开构造的路径 hash/xxx/xxx;
* 解析路径,检测分享存在,过期时间,下载次数,密码检测;
*/
public function sharePathInfo($path,$encode=false,$infoChildren=false){
$parse = KodIO::parse($path);
if(!$parse || $parse['type'] != KodIO::KOD_SHARE_LINK){return false;}
$this->showErrorStop = true;
$error = $this->initShare($parse['id']);
$this->showErrorStop = false;
if($error){
$GLOBALS['explorer.sharePathInfo.error'] = $error;
return false; // 不存在,时间过期,下载次数超出,需要登录,需要密码;
}
$truePath = $this->parsePath($path);
if($infoChildren){
$result = IO::infoWithChildren($truePath);
}else{
$result = IO::info($truePath);
}
if(!$result){return false;}
// 仅文件,判断预览;
$canView = _get($this->share,'options.notView') != '1';
$canDownload = _get($this->share,'options.notDownload') != '1';
if($this->shareOuterAuth){$canDownload = true;}
if($result['type'] == 'file' && !$canDownload && !$canView){
$GLOBALS['explorer.sharePathInfo.error'] = LNG('explorer.share.noViewTips');
return false;
}
if(is_array($result)){
if($encode){$result = $this->shareItemInfo($result);}
$result['shareID'] = $this->share['shareID'];
}
return $result;
}
public function shareInfoLast(){return $this->share;}
/**
* 通过分享hash获取分享信息;
* 提交分享密码
*/
public function get($get=false){
$field = array(
'shareHash','title','isLink','timeTo','numView','numDownload',
'options','createTime','sourceInfo',
);
$data = array_field_key($this->share,$field);
$data['shareUser'] = Model("User")->getInfoSimpleOuter($this->share['userID']);
$data['shareUser'] = $this->filterUserInfo($data['shareUser']);
$data['sourceInfo'] = $this->shareItemInfo($data['sourceInfo']);
if($get) return $data;
show_json($data);
}
/**
* 分享信息初始化;
* 拦截相关逻辑
*
* 过期拦截
* 下载次数限制拦截
* 登录用户拦截
* 密码检测拦截:如果参数有密码则检测并存储;错误则提示
* 下载次数,预览次数记录
*/
public function initShare($hash=''){
if($this->share && !isset($GLOBALS['isRootCall'])) return;
$this->share = $share = $this->model->getInfoByHash($hash);
$this->shareOuterAuth = Action('explorer.shareOut')->sendCheckAuth($this->share);
if(!$share || $share['isLink'] != '1'){
return $this->showError(LNG('explorer.share.notExist'),30100);
}
if($share['sourceInfo']['isDelete'] == '1'){
return $this->showError(LNG('explorer.share.notExist'),30100);
}
if(isset($GLOBALS['isRootCall']) && $GLOBALS['isRootCall']){return;} //后台任务队列获取属性,不做判断;
//外链分享有效性处理: 当分享者被禁用,没有分享权限,所在文件不再拥有分享权限时自动禁用外链分享;
if(!Action('explorer.authUser')->canShare($share)){
$userInfo = Model('User')->getInfoSimpleOuter($share['userID']);
$tips = '('.$userInfo['name'].' - '.LNG('common.noPermission').')';
return $this->showError(LNG('explorer.share.notExist') .$tips,30100);
}
//检测是否过期
if($share['timeTo'] && $share['timeTo'] < time()){
return $this->showError(LNG('explorer.share.expiredTips'),30101,$this->get(true));
}
if($this->shareOuterAuth){return;}
//检测下载次数限制
if( $share['options'] &&
$share['options']['downloadNumber'] &&
$share['options']['downloadNumber'] <= $share['numDownload'] ){
$msg = LNG('explorer.share.downExceedTips');
$pathInfo = explode('/', $this->in['path']);
if(!empty($pathInfo[1]) || is_ajax()) {
return $this->showError($msg,30102,$this->get(true));
}
return $this->showError($msg,30102,$this->get(true));
}
//检测是否需要登录
$user = Session::get("kodUser");
if( $share['options'] && $share['options']['onlyLogin'] == '1' && !is_array($user)){
return $this->showError(LNG('explorer.share.loginTips'),30103,$this->get(true));
}
//检测密码
$passKey = 'Share_password_'.$share['shareID'];
if( $share['password'] ){
if( isset($this->in['password']) && strlen($this->in['password']) < 500 ){
$code = md5(BASIC_PATH.Model('SystemOption')->get('systemPassword'));
$pass = Mcrypt::decode(trim($this->in['password']),md5($code));
if($pass == $share['password']){
Session::set($passKey,$pass);
}else{
return $this->showError(LNG('explorer.share.errorPwd'),false);
}
}
// 检测密码
if( Session::get($passKey) != $share['password'] ){
return $this->showError(LNG('explorer.share.needPwd'),30104,$this->get(true));
}
}
}
private function showError($msg,$code,$info=false){
if($this->showErrorStop){return $msg ? $msg:'error';}
$action = strtolower(ACT);
$tipsAction = array('fileout','filedownload');
if(in_array($action,$tipsAction)){return show_tips($msg);}
show_json($msg,$code,$info);
}
/**
* 权限检测
* 下载次数,预览次数记录
*/
private function authCheck(){
$ACT = strtolower(ACT);
$options = is_array($this->share['options']) ? $this->share['options'] : array();
$where = array("shareID"=>$this->share['shareID']);
// 分享者角色没有上传权限时, 忽略配置开启上传;
$actionUpload = array('fileupload','mkdir','mkfile');
$actionEdit = array('fileupload','mkdir','mkfile','pathrename','pathDelete','pathcopy','pathcute','pathcuteto','pathcopyto','pathpast','filesave');
$canUpload = $options['canUpload'] == '1';
$canEdit = $options['canEditSave'] == '1';
$canView = $options['notView'] != '1';
$canDownload = $options['notDownload'] != '1';
$outerAuth = $this->shareOuterAuth; // 对外联合分享访问, 权限采用外站分享的权限;
if($outerAuth == 'read' || $outerAuth == 'write'){$canView = true;$canDownload = true;}
if($outerAuth == 'write'){$canEdit = true;}
if($ACT == 'get'){
$this->model->where($where)->setAdd('numView');
$this->cacheShareClear();
}
//权限检测;是否允许下载、预览、上传;
$isDownload = ($ACT == 'fileout' && $this->in['download']=='1') || $ACT =='zipdownload' || $ACT =='filedownload';
if(!$canDownload && $isDownload){
$this->showError(LNG('explorer.share.noDownTips'),false);
}
if(!$canView && in_array($ACT,array('fileget','fileout','unziplist'))){
$this->showError(LNG('explorer.share.noViewTips'),false);
}
// TODO 有编辑权限,一定包含上传权限;
if(in_array($ACT,$actionUpload) && !$canEdit){
if($canUpload && !Action('user.authRole')->authCanUser('explorer.upload',$this->share['userID'])){$canUpload = false;}
if($canUpload && isset($this->in['path']) && !$this->checkPathAuth($this->in['path'])){$canUpload = false;}
if(!$canUpload){$this->showError(LNG('explorer.noPermissionWriteAll'),false);}
}
if(in_array($ACT,$actionEdit) && !in_array($ACT,$actionUpload)){// 目的地检测;必须为当前分享文件夹下子内容;
if($canEdit && !Action('user.authRole')->authCanUser('explorer.edit',$this->share['userID'])){$canEdit = false;}
if($canEdit && isset($this->in['path']) && !$this->checkPathAuth($this->in['path'])){$canEdit = false;}
if($canEdit && isset($this->in['dataArr']) && !$this->checkPathAuth($this->in['dataArr'],true)){$canEdit = false;}
if($canEdit && $outerAuth != 'write' && Model('SystemOption')->get('shareLinkAllowEdit') == '0'){$canEdit = false;}
if(!$canEdit){$this->showError(LNG('explorer.noPermissionWriteAll'),false);}
}
// 下载计数; 分片下载时仅记录起始为0的项(并忽略长度为0的请求),忽略head请求;
if($isDownload){
if(!Action('admin.log')->checkHttpRange()){return;}
$this->model->where($where)->setAdd('numDownload');
$this->cacheShareClear();
}
}
private function checkPathAuth($path,$isArray = false){
if(!$this->share || !$this->share['shareHash']){return false;}
$prePath = "{shareItemLink:".$this->share['shareHash']."}";
if(!$isArray){return strpos(rawurldecode($path),$prePath) === 0 ? true:false;}
$data = json_decode($this->in['dataArr'],true);
if(!is_array($data)){return false;}
foreach ($data as $item){
if(strpos(rawurldecode($item['path']),$prePath) !== 0){return false;}
}
return true;
}
// 清除分享方法缓存
private function cacheShareClear(){
$this->model->cacheFunctionClear('listSimple', $this->share['userID']);
$this->model->cacheFunctionClear('getInfoShare', $this->share['shareID']);
}
/**
* 检测并获取真实路径;
*/
private function parsePath($path,$allowNotExist=false){
if(request_url_safe($path)) return $path;//压缩包支持;
$rootSource = $this->share['sourceInfo']['path'];
$parse = KodIO::parse($path);
if(!$parse || $parse['type'] != KodIO::KOD_SHARE_LINK ||
$this->share['shareHash'] != $parse['id'] ){
show_json(LNG('common.noPermission'),false);
}
$pathInfo = IO::infoFullSimple($rootSource.$parse['param']);
if(!$pathInfo){
if($allowNotExist){return $rootSource.$parse['param'];}
show_json(LNG('common.pathNotExists'),false);
}
return $pathInfo['path'];
}
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++) {
$path = $this->parsePath($fileList[$i]['path']);
$this->fileCheckDownload($path);
if($this->in['getChildren'] == '1'){
$pathInfo = IO::infoWithChildren($path);
}else{
$pathInfo = IO::infoFull($path);
}
if(!is_array($pathInfo)){continue;}
if(!array_key_exists('hasFolder',$pathInfo)){
$has = IO::has($path,true);
if(is_array($has)){$pathInfo = array_merge($pathInfo,$has);}
}
$pathInfoOut = $this->shareItemInfo($pathInfo);
if(is_array($pathInfo['fileInfo'])){$pathInfoOut['fileInfo'] = $pathInfo['fileInfo'];} // 用户hash获取等;
$pathInfoOut = Action('explorer.list')->pathInfoCover($pathInfoOut);//path参数需要是外链路径;
if(is_array($pathInfoOut['fileInfo'])){unset($pathInfoOut['fileInfo']);}
$result[] = $pathInfoOut;
}
if(count($fileList) == 1){
// 单个文件属性; 没有仅用预览,则开放预览链接;
$canDownload = _get($this->share,'options.notDownload') != '1';
if($this->shareOuterAuth){$canDownload = true;}
if($result[0]['type'] == 'file' && $canDownload ){
$param = "shareID=".$this->share['shareHash']."&path=".rawurlencode($result[0]['path']);
$param .= '&name=/'.rawurlencode($result[0]['name']);
$result[0]['downloadPath'] = urlApi('explorer/share/fileOut',$param);
}
show_json($result[0]);
}
show_json($result);
}
//输出文件
public function fileOut(){
$path = rawurldecode($this->in['path']);//允许中文空格等;
if(request_url_safe($path)){header('Location:'.$path);exit;}
$path = $this->parsePath($path);
$this->fileCheckDownload($path);
$isDownload = $this->in['download'] == '1';
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){Action('explorer.index')->updateLastOpen($path);}
if($info['size'] >= 1024*200 &&
function_exists('imagecolorallocate') &&
in_array($info['ext'],$imageThumb)
){return IO::fileOutImage($path,$this->in['width']);}
}
Action('explorer.index')->fileOutUpdate($path,$isDownload);
}
public function fileDownload(){
$this->in['download'] = 1;
$this->fileOut();
}
public function fileOutBy(){
$add = kodIO::pathUrlClear(rawurldecode($this->in['add']));
$path = rawurldecode($this->in['path']);
if(request_url_safe($path)){header('Location:'.$path);exit;}
$distPath = kodIO::pathTrue($path.'/../'.$add);
$this->in['path'] = rawurlencode($distPath);
if(isset($this->in['type']) && $this->in['type'] == 'getTruePath'){
show_json($distPath,true);
}
$this->fileOut();
}
private function call($action,$parsePath=false){
$self = $this;
if(isset($this->in['path']) && !$parsePath){
$this->in['path'] = $this->parsePath($this->in['path'],true);
}
ActionCallResult($action,function(&$res) use($self){
if(!$res['code']){return;}
if(ACT == 'fileSave'){$res['info'] = $this->shareItemInfo($res['info']);return;}
// 粘贴,拖拽情况处理;
if(ACT == 'pathCuteTo' || ACT == 'pathCopyTo' || ACT == 'pathPast'){
$resNew = $self->callParsePast($res);
if($resNew && $resNew['info']){$res['info'] = $resNew['info'];}
if($resNew && $resNew['infoMore']){$res['infoMore'] = $resNew['infoMore'];}
return;
}
if(!$res['info'] || !is_string($res['info'])){return;}
$pathInfo = $self->shareItemInfo(IO::info($res['info']));
$res['info'] = $pathInfo['path'];
});
}
public function fileUpload(){$this->call("explorer.upload.fileUpload");}
public function mkfile(){$this->call("explorer.index.mkfile");}
public function mkdir(){$this->call("explorer.index.mkdir");}
public function pathDelete(){$this->call("explorer.index.pathDelete");}
public function pathRename(){$this->call("explorer.index.pathRename");}
// path,pathArr都不处理路径为source,确保io一致,否则source内容外链分享:新建再删除,会产生脏数据
public function pathCuteTo(){$this->call("explorer.index.pathCuteTo",true);}
public function pathCopyTo(){$this->call("explorer.index.pathCopyTo",true);}
public function pathCute(){$this->call("explorer.index.pathCute",true);}
public function pathCopy(){$this->call("explorer.index.pathCopy",true);}
public function pathPast(){$this->call("explorer.index.pathPast");}
public function fileSave(){$this->call("explorer.editor.fileSave");}
public function callParsePast($res){
if(!is_array($res['info']) || !isset($res['info'][0])){return false;}
foreach($res['info'] as $i=>$path){
$pathInfo = $this->shareItemInfo(IO::info($res['info'][$i]));
$res['info'][$i] = $pathInfo['path'];
if(is_array($res['infoMore']['listTo'])){
$res['infoMore']['listTo'][$i] = $pathInfo['path'];
}
}
if(is_array($res['infoMore']) && isset($res['infoMore']['pathTo'])){
$res['infoMore']['pathTo'] = $_REQUEST['path'];
}
return $res;
}
public function fileGet(){
$pageNum = 1024 * 1024 * 10;$self = $this;
$this->in['pageNum'] = isset($this->in['pageNum']) ? $this->in['pageNum'] : $pageNum;
$this->in['pageNum'] = $this->in['pageNum'] >= $pageNum ? $pageNum : $this->in['pageNum'];
$this->in['path'] = $this->parsePath($this->in['path']);
$this->fileCheckDownload($this->in['path']);
ActionCallResult("explorer.editor.fileGet",function(&$res) use($self){
if(!$res['code']){return;}
$pathDisplay = $res['data']['pathDisplay'];
$res['data'] = $self->shareItemInfo($res['data']);
if($pathDisplay && substr($pathDisplay,0,1) == '['){$res['data']['pathDisplay'] = $pathDisplay;}
if(is_array($res['data']['fileInfo'])){unset($res['data']['fileInfo']);}
});
}
// 文件下载权限校验
public function fileCheckDownload($path){
$parse = KodIO::parse($path);
if($parse['type'] == KodIO::KOD_SOURCE){ // 上层包含密码时处理;
$errorMsg = Action('explorer.listPassword')->authCheck(IO::info($path),'download');
if($errorMsg){show_json($errorMsg,false,1102);}
}
}
// 压缩包内文本文件请求(不再做权限校验; 通过文件外链hash校验处理)
public function fileGetHash(){
$pageNum = 1024 * 1024 * 10;
$this->in['pageNum'] = isset($this->in['pageNum']) ? $this->in['pageNum'] : $pageNum;
$this->in['pageNum'] = $this->in['pageNum'] >= $pageNum ? $pageNum : $this->in['pageNum'];
// ActionCall("explorer.editor.fileGet");exit;
$url = $this->in['path'];
$urlInfo = parse_url_query($url);
if( !isset($urlInfo["explorer/share/unzipListHash"]) &&
!isset($urlInfo["accessToken"])){
show_json(LNG('common.pathNotExists'),false);
}
$index = json_decode(rawurldecode($urlInfo['index']),true);
$zipFile = $this->fileHash(rawurldecode($urlInfo['path']));
$filePart = IOArchive::unzipPart($zipFile,$index ? $index:'-1');
if(!$filePart || !IO::exist($filePart['file'])){
show_json(LNG('common.pathNotExists'),false);
}
Action("explorer.editor")->fileGetMake($filePart['file'],IO::info($filePart['file']),$url);
}
public function pathList(){
$path = $this->in['path'];
$pathParse = KodIO::parse($path);
if($pathParse['type'] == KodIO::KOD_SEARCH){
$searchParam = Action('explorer.listSearch')->parseSearch($pathParse['param']);
$this->parsePath($searchParam['parentPath']); //校验path;
$data = Action('explorer.listSearch')->listSearchPath($pathParse);
Action('explorer.list')->pageParse($data);
Action('explorer.list')->pathListParse($data);
$data['current'] = Action('explorer.list')->pathCurrent($path);
$data['thisPath'] = $path;
}else{
$allowPath = explode(',','{block:fileType}'); //允许的目录;虚拟目录;
if(!in_array($path,$allowPath)){$this->parsePath($path);}
$data = Action('explorer.list')->path($path);
}
// 默认自动展开文件夹层级; deep=1/2(文档预览模式,优化请求)
if(isset($this->in['deep']) && is_array($data['folderList']) &&
$this->in['deep'] >= 1){
foreach ($data['folderList'] as $key=>$item){
$child = Action('explorer.list')->path($item['path']);
$item['children'] = $child;$data['folderList'][$key] = $item;
if($this->in['deep'] == 1 || !is_array($child['folderList'])){continue;}
foreach($child['folderList'] as $key2=>$item2) {
$child2 = Action('explorer.list')->path($item2['path']);
$item2['children'] = $child2;
$data['folderList'][$key]['children']['folderList'][$key2] = $item2;
}
}
}
// 文件快捷方式处理;
if($data && $data['fileList']){
foreach($data['fileList'] as &$file){
if(is_array($file['fileInfo'])){unset($file['fileInfo']);}
$this->filterOexeContent($file);
}
}
show_json($data);
}
/**
* 分享压缩下载
* 压缩和下载合并为同一方法
*/
public function zipDownload(){
$dataArr = json_decode($this->in['dataArr'],true);
if($this->in['zipClient'] == '1'){
$result = Action('explorer.index')->zipDownloadClient($dataArr);
$sharePath = $this->share['sourcePath'];
$shareLink = "{shareItemLink:".$this->share['shareHash']."}/";
foreach($result as $i => $item){
if(!$item['filePath']){continue;}
$result[$i]['filePath'] = str_replace($sharePath,$shareLink,$item['filePath']);
}
show_json($result,true);return;
}
$this->zipSupportCheck();
foreach($dataArr as $i => $item){
$dataArr[$i]['path'] = $this->parsePath($item['path']);
}
$this->in['dataArr'] = json_encode($dataArr);
Action('explorer.index')->zipDownload();
}
public function fileDownloadRemove(){
Action('explorer.index')->fileDownloadRemove();
}
public function unzipList(){
$this->zipSupportCheck();
$this->in['path'] = $this->parsePath($this->in['path']);
Action('explorer.index')->unzipList();
}
public function unzipListHash(){
$this->zipSupportCheck();
$this->in['path'] = $this->fileHash($this->in['path']);
Action('explorer.index')->unzipList();
}
private function zipSupportCheck(){
if(Model('SystemOption')->get('shareLinkZip') == '1') return true;
show_json(LNG('admin.setting.shareLinkZipTips'),false);
}
public function shareItemInfo($item){
$rootPath = $this->share['sourceInfo']['pathDisplay'];
// 物理路径,io路径;
if($this->share['sourceID'] == '0'){
$rootPath = KodIO::clear($this->share['sourcePath']);
// io路径(本地磁盘挂载时); 外链分享搜索时会处理为真实路径情况处理;
if(substr($item['path'],0,strlen($rootPath)) != $rootPath){
$io = IO::init($rootPath);
$rootPath = $io->path;
}
}
$item['pathDisplay'] = $item['pathDisplay'] ? $item['pathDisplay']:$item['path'];
$field = array(
'name','path','type','size','ext','searchTextFile',
'createUser','modifyUser','createTime','modifyTime','sourceID','parentLevel',
'hasFolder','hasFile','children','targetType','targetID','pageInfo','searchContentMatch',
'base64','content','charset','oexeContent','oexeSourceInfo','fileInfoMore','fileInfo','fileThumb',
// 'isReadable','isWriteable',//(不处理, 部门文件夹分享显示会有区分)
);
$theItem = array_field_key($item,$field);
$path = KodIO::makePath(KodIO::KOD_SHARE_LINK,$this->share['shareHash']);
$name = $this->share['sourceInfo']['name'];
$theItem['pathDisplay'] = ltrim(substr($item['pathDisplay'],strlen($rootPath)),'/');
$theItem['path'] = rtrim($path,'/').'/'.$theItem['pathDisplay'];
$theItem['pathDisplay'] = $name.'/'.$theItem['pathDisplay'];
if(is_array($item['metaInfo'])){
$picker = 'user_sourceCover,folderPassword';
$theItem['metaInfo'] = array_field_key($item['metaInfo'],explode(',',$picker));
}
if($theItem['type'] == 'folder'){$theItem['ext'] = 'folder';}
if(is_array($theItem['createUser'])) $theItem['createUser'] = $this->filterUserInfo($theItem['createUser']);
if(is_array($theItem['modifyUser'])) $theItem['modifyUser'] = $this->filterUserInfo($theItem['modifyUser']);
return $theItem;
}
private function filterOexeContent(&$theItem){
if($theItem['type'] != 'file' || $theItem['ext'] != 'oexe') return;
if(!isset($theItem['oexeContent'])) return;
if($theItem['oexeContent']['type'] != 'path') return;
$rootPath = $this->share['sourceInfo']['pathDisplay'];
if($this->share['sourceID'] == '0'){
$rootPath = KodIO::clear($this->share['sourcePath']);
$pathDisplay = $theItem['oexeContent']['value'];
}else{
$sourceInfo = IO::info($theItem['oexeContent']['value']);
$pathDisplay = $sourceInfo['pathDisplay'];
}
$path = KodIO::makePath(KodIO::KOD_SHARE_LINK,$this->share['shareHash']);
$pathDisplay = ltrim(substr($pathDisplay,strlen($rootPath)),'/');
$theItem['oexeContent']['value'] = rtrim($path,'/').'/'.$pathDisplay;
if($sourceInfo){
$sourceInfo['path'] = $theItem['oexeContent']['value'];
$theItem['oexeSourceInfo'] = $sourceInfo;
}
}
private function filterUserInfo($userInfo){
$name = !empty($userInfo['nickName']) ? $userInfo['nickName'] : $userInfo['name'];
unset($userInfo['nickName'], $userInfo['name']);
$userInfo['nameDisplay'] = $this->parseName($name);
$userInfo['userID'] = 'user:'.$userInfo['userID'];
return $userInfo;
}
private function parseName($name){
$len = mb_strlen($name);
return $len > 3 ? mb_substr($name,0,3).'***':$name;
}
/**
* 分享文件举报
* @return void
*/
public function report(){
$data = Input::getArray(array(
'path' => array('check' => 'require'),
'type' => array('check' => 'in', 'param' => array('1','2','3','4','5')),
'desc' => array('default' => '')
));
$fileID = 0;
if($this->share['sourceInfo']['type'] == 'file') {
$info = $this->sharePathInfo($data['path']);
$fileID = $info['fileInfo']['fileID'];
}
$data['shareID'] = $this->share['shareID'];
$data['sourceID'] = $this->share['sourceID'];
$data['title'] = $this->share['title'];
$data['fileID'] = $fileID;
$res = $this->model->reportAdd($data);
show_json('OK', !!$res);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/shareOut.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
// 对外站点联合分享处理;
class explorerShareOut extends Controller{
private $model;
function __construct(){
parent::__construct();
$GLOBALS['config']['jsonpAllow'] = true;
}
// 检测是否允许接收外站联合分享; 分享发起端,前端添加编辑用户时检测
public function shareCheck(){
$data = $this->shareParamParse();
if(!$data['_authTo']){show_json(LNG('explorer.shareOut.errorTarget'),false);}
show_json("ok:check",true);
}
// 接收处理: 自动生成协作分享--独立IO;个人中心显示与我协作;
public function shareMake(){
$data = $this->shareParamParse();
$model = Model('Share');
$siteFrom = rtrim(get_url_link($data['siteFrom']),'/');
$sourcePath = 'share@'.intval($data['shareID']).'@'.$siteFrom;
$shareFind = $model->where(array('userID'=>0,'sourcePath'=>$sourcePath))->find();
if(!$data['_authTo']){
if($shareFind){$model->remove($shareFind['shareID']);}
if(!$data['shareOut']){show_json('ok',true);}
show_json(LNG('explorer.shareOut.errorTarget'),false);
}
// 检测来源站点,并且检测否启用了外部站点分享功能;
$apiFrom = $siteFrom.'/index.php?explorer/shareOut/sendCheckAllow';
$response = url_request($apiFrom,'GET',array(),false,false,true,6);
if(_get($response,'data.info') != 'kodbox'){// 不是kodbox站点输出则忽略;
show_json(LNG('explorer.shareOut.errorNetwork').",".$siteFrom,false);
}else if(!_get($response,'data.code')){
show_json(_get($response,'data.data'),false);
}
$saveData = array(
'isLink' => '0','isShareTo' => '1',
'password' => '__SHSRE_OUTER__',
'sourcePath'=> $sourcePath,
'authTo' => $data['_authTo'],
'options' => array(
'site' => $siteFrom,
'shareID' => $data['shareID'],
'shareHash' => $data['shareHash'],
'shareUser' => $data['shareUser'],
'sourceInfo' => $data['sourceInfo'],
'shareTarget' => $data['_shareTarget'],
),
);
if($shareFind){
$model->shareEdit($shareFind['shareID'],$saveData);
$shareID = $shareFind['shareID'];
}else{
$shareID = $model->shareAddSystem(0,$saveData);
$model->shareEdit($shareID,$saveData);
}
// show_json([$model->getInfo($shareID),$model->getInfo($data['shareID']),$saveData,$data]);
show_json("ok:".($shareFind ? 'edit':'add').';shareID='.$shareID,true);
}
// 获取分享对象信息; 对象类型/对象id/权限id;
private function shareParamParse(){
$data = Input::getArray(array(
'_check' => array("check"=>"require"),
'siteFrom' => array("check"=>"url"),
'siteTo' => array("check"=>"url"),
'shareID' => array("check"=>"number"),
'shareHash' => array("check"=>"require"),
'shareUser' => array("check"=>"require"),
'sourceInfo'=> array("check"=>"json","default"=>array()),
'shareOut' => array("check"=>"json","default"=>array()),// [{target,auth},...]
));
$this->tableInit();
$config = Model('SystemOption')->get();
$checkKey = Mcrypt::decode($data['_check'],'kodShareOut');
$limitKey = 'shareOutRecive-'.$data['siteFrom'];
if($config['shareOutAllowRecive'] != '1'){show_json(LNG('explorer.shareOut.errorDisableReceive'),false);}
if($data['siteFrom'] != $checkKey){show_json(LNG('explorer.share.errorParam'),false);}
if(!Cache::limitCall($limitKey,5,10,false)){show_json(LNG('explorer.shareOut.errorCallLimit'),false);}
$authList = $this->authListMake();
$data['_shareTarget'] = array();$data['_authTo'] = array();
$dataAdd = array();
foreach($data['shareOut'] as $item){
$target = $item['target'];
$targetType = SourceModel::TYPE_USER;$targetID = 0;
if(substr($target,0,strlen('user:')) === 'user:'){
$dataInfo = Model('User')->getInfoSimple(substr($target,strlen('user:')));
if($dataInfo){$targetID = $dataInfo['userID'];}
}else if(substr($target,0,strlen('group:')) === 'group:'){
$dataInfo = Model('Group')->getInfoSimple(substr($target,strlen('group:')));
if($dataInfo){$targetID = $dataInfo['groupID'];$targetType = SourceModel::TYPE_GROUP;}
}else{
$dataInfo = Model('User')->userLoginFind($target);
if($dataInfo){$targetID = $dataInfo['userID'];}
}
$authID = $authList[$item['auth']];
$dataAddKey = $targetType.'-'.$targetID;// 去重处理;
if(!$targetID || !$authID || $dataAdd[$dataAddKey]){continue;}
$dataAdd[$dataAddKey] = true;
$_item = array_field_key($item,array('target','secret','auth'));
$data['_shareTarget'][] = array_merge($_item,array('authID'=>$authID,'to'=>$target.'@'.$data['siteTo']));
$data['_authTo'][] = array('targetType'=>$targetType,'targetID'=>$targetID,"authID"=>$authID);
}
return $data;
}
// 权限映射到当前站点文档权限;
private function authListMake(){
return array(
'read' => Model('Auth')->findAuthMax(
AuthModel::AUTH_SHOW | AuthModel::AUTH_VIEW | AuthModel::AUTH_DOWNLOAD,
AuthModel::AUTH_UPLOAD | AuthModel::AUTH_EDIT | AuthModel::AUTH_REMOVE
),
'write' => Model('Auth')->findAuthMax(
AuthModel::AUTH_SHOW | AuthModel::AUTH_VIEW | AuthModel::AUTH_DOWNLOAD | AuthModel::AUTH_UPLOAD | AuthModel::AUTH_EDIT | AuthModel::AUTH_REMOVE,
AuthModel::AUTH_ROOT
),
);
}
// apiKey检测(管理员后台,添加授信站点时前端发起请求)
public function shareCheckApiKey(){
$config = Model('SystemOption')->get();
$checkKey = Mcrypt::decode($this->in['apiKey'],'kodShareOut');
if($config['shareOutAllowRecive'] != '1'){show_json(LNG('explorer.shareOut.errorDisableReceive'),false);}
if($config['shareOutSiteApiKey'] != $checkKey){show_json(LNG('explorer.shareOut.errorApiKey'),false);}
show_json("ok:check",true);
}
// 授信目标站点组织架构获取;分享时前端发起获取;
public function shareSafeGroup(){
$config = Model('SystemOption')->get();
$checkKey = Mcrypt::decode($this->in['sk'],$config['shareOutSiteApiKey']);
if($config['shareOutAllowRecive'] != '1'){show_json(LNG('explorer.shareOut.errorDisableReceive'),false);}
if($checkKey != 'kodShareOutGroup'){show_json(LNG('explorer.shareOut.errorApiKey').'(timeout)',false);}
$GLOBALS['isRoot'] = true;
$methodMap = array(
'groupList' => array('action'=>'admin.group.get','param'=>'parentID'),
'groupSearch' => array('action'=>'admin.group.search','param'=>'words'),
'memberList' => array('action'=>'admin.member.get','param'=>'groupID'),
'memberSearch' => array('action'=>'admin.member.search','param'=>'words'),
);
$methodInfo = $methodMap[$this->in['method']];
if(!$methodInfo){show_json('method error!',false);}
ActionCallResult($methodInfo['action'],function(&$res) use($self){
if(!$res['code']){return;}
$index = $GLOBALS['in']['siteIndex'];
$fieldGroup = array('groupID','name','groupPath','hasChildren','hasChildrenMember');
$fieldUser = array('userID','name','nickName','avatar');
foreach($res['data']['list'] as $i=>$item){
if($item['groupID']){$item = array_field_key($item,$fieldGroup);}
if($item['userID']){$item = array_field_key($item,$fieldUser);}
$item['siteIndex'] = $GLOBALS['in']['siteIndex'];
$res['data']['list'][$i] = $item;
}
});
}
// 接收端, 成员用户退出协作处理
public function shareUserExit($siteFrom,$shareID,$secret){
if(!$siteFrom || !$shareID || !$secret){return false;}
$apiFrom = $siteFrom.'/index.php?explorer/shareOut/sendShareUserExit';
$param = array('shareID'=>$shareID,'secret'=>$secret);
$response = url_request($apiFrom,'POST',$param,false,false,true,3);
return $response['data'];
}
//==================== 作为[联合分享发送方]提供的接口 ===================
// 外部用户访问权限校验; return: false/read/write; (接收端内部IO向发起端请求, 发起端校验处理);
// 校验通过返回对应权限; 不通过则默认使用外链分享各个限制;
public function sendCheckAuth($shareInfo){
if(!$this->in['sk']){return false;}
if(Model('SystemOption')->get('shareOutAllowSend') != '1'){return false;}
$decode = Mcrypt::decode($this->in['sk'],'kodShareOut').'';
$dataArr = explode('$@$',$decode);
$authTo = array_find_by_field($shareInfo['options']['shareOut'],'to',$dataArr[1]);
if(!is_array($authTo) || $authTo['secret'] != $dataArr[0]){return false;}
$GLOBALS['fileEncodeDisable'] = '1';// 屏蔽外链分享,文件内容加密(文档水印及安全--启用文件加密启用时)
return $authTo['auth'];
}
// 接收时向发起站点做访问校验处理; 接收端接收到推送时向发起端后端请求(shareMake中);
public function sendCheckAllow(){
$config = Model('SystemOption')->get();
if($config['shareLinkAllow'] != '1'){show_json(LNG('explorer.shareOut.errorDisableShare'),false,'kodbox');}
if($config['shareOutAllowSend'] != '1'){show_json(LNG('explorer.shareOut.errorDisableSend'),false,'kodbox');}
show_json("ok:check",true,'kodbox');
}
// 分享端,接收成员用户退出协作处理;
public function sendShareUserExit(){
$config = Model('SystemOption')->get();
if($config['shareLinkAllow'] != '1'){show_json(LNG('explorer.shareOut.errorDisableShare'),false,'kodbox');}
if($config['shareOutAllowSend'] != '1'){show_json(LNG('explorer.shareOut.errorDisableSend'),false,'kodbox');}
$data = Input::getArray(array(
'shareID' => array("check"=>"number"),
'secret' => array("check"=>"require"),
));
$model = Model('Share');
$shareInfo = $model->getInfo($data['shareID']);
$shareOut = _get($shareInfo,'options.shareOut',array());
$shareOutNew = array();$hasFind = false;
foreach($shareOut as $item){
if($item['secret'] != $data['secret']){$shareOutNew[] = $item;continue;}
$hasFind = true;
}
if(!$hasFind){show_json(LNG('explorer.share.notExist'),false,'kodbox');}
$shareOptions = $shareInfo['options'];
$shareOptions['shareOut'] = $shareOutNew;
if(!$shareOutNew){unset($shareOptions['shareOut']);}
$model->shareEdit($data['shareID'],array('isLink'=>'1','options'=>$shareOptions));
$model->cacheFunctionClear('listSimple',$shareInfo['userID']);// 自己分享列表信息更新;
show_json('ok',true,'kodbox');
}
// 当前站点分享信息获取时,授信站点列表获取(apiKey加密); 供前端显示用(前端获取用户部门信息)
public function sendShareSiteAppend($shareInfo){
$config = Model('SystemOption')->get();
$this->tableInit();
if(!$shareInfo || !is_array($shareInfo)){return $shareInfo;}
if($config['shareLinkAllow'] != '1' || $config['shareOutAllowSend'] != '1'){return $shareInfo;}
$result = array();$listAdd = array();
$siteList = json_decode(_get($config,'shareOutSiteSafe',''),true);
if(!is_array($siteList)){$siteList = array();}
foreach($siteList as $site){
if(!$site || $site['isOpen'] != '1' || !$site['apiKey']){continue;}
if($listAdd[$site['url']]){continue;} // 去重;
$result[] = array(
'url' => $site['url'],
'name' => $site['name'],
'sk' => Mcrypt::encode('kodShareOutGroup',$site['apiKey'],600),//有效期10分钟;
);
$listAdd[$site['url']] = true;
}
$shareInfo['shareOutSite'] = $result;
return $shareInfo;
}
// 表结构初始化; varchar(1000)=>text (65536字符);
private function tableInit(){
if(Model('SystemOption')->get('shareOutInit')){return;}
Model('SystemOption')->set('shareOutInit','1');
$sql = "ALTER TABLE `share` CHANGE `options` `options` text COLLATE 'utf8_general_ci' NULL COMMENT 'json 配置信息' AFTER `numDownload`;";
if(stristr($this->config['database']['DB_TYPE'],'sqlite')){$sql = '';}
if($sql){Model()->db()->execute($sql);}
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/tag.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 标签管理:增删改查、置顶置底;
* listData(); //tag列表
* add(); //tag添加 [参数]:name/style
* edit(); //重命名Tag [参数]:tagID,name/style
* remove(); //删除tag [参数]:tagID
* moveTop(); //置顶 [参数]:tagID
* moveBottom(); //置底 [参数]:tagID
* resetSort(); //重置排序,更具id的顺序重排; [参数]:tagList:逗号隔开的id
* -------
* sourceAddToTag(); //添加文档到tag [参数]:tagID/sourceID
* sourceResetTag(); //重置某个文档所在的tag [参数]:tagList:逗号隔开的id/sourceID
* sourceRemoveFromTag(); //将文档从某个tag中移除 [参数]:tagID/sourceID
*/
class explorerTag extends Controller{
private $model;
function __construct(){
parent::__construct();
$this->model = Model('UserTag');
$this->modelSource = Model('UserTagSource');
}
/**
* tag列表
*/
public function get() {
show_json($this->data());
}
private function data(){
return $this->model->listData();
}
/**
* 用户文件标签列表
*/
public function tagList(){
$this->initUserData();
$dataList = $this->data();
$tagSource = $this->modelSource->listData();
$list = array();
foreach ($dataList as $item) {
$style = $item['style']? $item['style'] : 'label-grey-normal';
$find = array_filter_by_field($tagSource,'tagID',$item['id']);
$list[$item['id']] = array(
"name" => $item['name'],
"path" => KodIO::makeFileTagPath($item['id']),
"icon" => 'tag-label label ' . $style,
'tagInfo' => $item,
'tagHas' => count($find),
'pathDesc' => LNG('explorer.pathDesc.tagItem'),
);
}
return $list;
}
private function initUserData(){
if(Model('UserOption')->get('userTagInit','flag') == 'ok') return;
$list = $GLOBALS['config']['settings']['userDefaultTag'];
foreach ($list as $item) {
$this->model->add(LNG($item['name']),$item['style']);
}
Model('UserOption')->set('userTagInit','ok','flag');
}
public function listSource($tags){
$groupPre = 'group-';
if(strstr($tags,$groupPre)){
$tags = explode('-',substr($tags,strlen($groupPre)));
return Action("explorer.tagGroup")->listSource($tags[0],array_slice($tags,1));
}
$tags = explode('-',$tags);
$tags = $tags[0] ? $tags : false;
$result = Model("Source")->listUserTag($tags);
$tagInfo= $this->tagsInfo($tags);
$tagInfo['pathAddress'] = array(
array("name"=> LNG('explorer.userTag.title'),"path"=>'{block:fileTag}/'),
array("name"=> $tagInfo['name'],"path"=>$this->in['path']),
);
$tagInfo['pathDesc'] = LNG('explorer.tag.pathDesc');
if(!$result){$result = array("fileList"=>array(),'folderList'=>array());}
$result['currentFieldAdd'] = $tagInfo;
$result['fileList'] = $this->_checkExists($result['fileList']);
$result['folderList'] = $this->_checkExists($result['folderList']);
return $result;
}
// 自动清理不存在的内容(仅限物理路径, 其他io路径由于比较耗时暂不处理,手动处理)
private function _checkExists($list){
if(!$list){return array();}
foreach($list as $key => &$item){
if(substr($item['path'],0,1) == '{'){continue;} // 仅处理物理路径;
if(!file_exists($item['path'])){
// $item['exists'] = false;
unset($list[$key]);
$this->modelSource->removeBySource($item['path']);
}
};unset($item);
return $list;
}
// 普通路径追加标签信息; source路径会已经自动添加;
public function tagAppendItem(&$item){
if(isset($item['sourceInfo']['tagInfo'])){return $item;}
static $listPathMap = false;
static $tagInfoArr = false;
if($listPathMap === false){ // 缓存处理;
$this->modelSource->cacheFunctionClear('listData',USER_ID);
$listPathMap = $this->modelSource->listData(); // model查询缓存;
$listPathMap = array_to_keyvalue_group($listPathMap,'path','tagID');
$tagInfoArr = $this->model->listData();
$tagInfoArr = array_to_keyvalue($tagInfoArr,'id');
}
if(!$tagInfoArr || !$listPathMap){return $item;}
$item['sourceInfo']['tagInfo'] = 0;
$path = $item['path'];$path1 = rtrim($item['path'],'/');$path2 = rtrim($item['path'],'/').'/';
$findItem = isset($listPathMap[$path]) ? $listPathMap[$path]:false;
$findItem = (!$findItem && isset($listPathMap[$path1])) ? $listPathMap[$path1]:$findItem;
$findItem = (!$findItem && isset($listPathMap[$path2])) ? $listPathMap[$path2]:$findItem;
if(!$findItem){return $item;}
$item['sourceInfo']['tagInfo'] = array();
foreach ($findItem as $tagID) {
$item['sourceInfo']['tagInfo'][] = array(
"tagID" => $tagInfoArr[$tagID]['id'],
"name" => $tagInfoArr[$tagID]['name'],
"style" => $tagInfoArr[$tagID]['style'],
);
}
return $item;
}
private function tagsInfo($tags){
$info = false;
$styleDefault = 'tag-label label label-blue-normal';
if(!$tags){return array('name'=>'--','icon'=>$styleDefault);}
$tagList = $this->model->listData();
foreach ($tagList as $item) {
$icon = 'tag-label label '.$item['style'];
if(!in_array($item['id'],$tags)) continue;
if(!$info){$info = array('name'=>$item['name'],'icon'=>$icon);continue;}
$info['name'] .= ','.$item['name'];
}
if(count($tags) > 1){$info['icon'] = $info['icon'].' label-mutil';}
return $info;
}
/**
* tag添加
*/
public function add(){
$data = Input::getArray(array(
"name" => array("check"=>"require"),
"style" => array('check'=>"require"),
));
if(count($this->data()) > $GLOBALS['config']['systemOption']['tagNumberMax']){
show_json(LNG("common.numberLimit"),false);
}
$res = $this->model->add($data['name'],$data['style']);
$msg = $res ? LNG('explorer.success') : LNG('explorer.repeatError');
show_json($msg,!!$res,$this->data());
}
/**
* 重命名Tag
*/
public function edit() {
$data = Input::getArray(array(
"tagID" => array("check"=>"int"),
"name" => array('default'=>null),
"style" => array('default'=>null),
));
$res = $this->model->update($data['tagID'],$data);
$msg = $res ? LNG('explorer.success') : LNG('explorer.repeatError');
show_json($msg,!!$res,$this->data());
}
/**
* 删除tag
*/
public function remove(){
$tagID = Input::get('tagID',"int");
$res = $this->model->remove($tagID);
$this->modelSource->removeByTag($tagID);
$msg = $res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res,$this->data());
}
/**
* 置顶
*/
public function moveTop() {
$tagID = Input::get('tagID',"int");
$res = $this->model->moveTop($tagID);
$msg = $res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res,$this->data());
}
/**
* 置底
*/
public function moveBottom() {
$tagID = Input::get('tagID',"int");
$res = $this->model->moveBottom($tagID);
$msg = $res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res,$this->data());
}
/**
* 重置排序,根据id的顺序重排;
*/
public function resetSort() {
$idList = Input::get('tagList',"require");
$idArray = explode(',',$idList);
if(!$idArray) {
show_json(LNG('explorer.error'),false);
}
$res = $this->model->resetSort($idArray);
$msg = $res ? LNG('explorer.success') : LNG('explorer.error');
show_json($msg,!!$res,$this->data());
}
//======== tag关联资源管理 =========
//将文档从某个tag中移除
public function filesRemoveFromTag(){
$data = Input::getArray(array(
"tagID" => array("check"=>"int"),
"files" => array("check"=>"require"),
));
$data['files'] = str_replace("__*@*__",',',$data['files']);
$files = explode(',',$data['files']);
if(!$files){
show_json(LNG('explorer.error'),false);
}
$res = $this->modelSource->removeFromTag($files,$data['tagID']);
if(!$res && count($files) == 1){ // 部分老数据处理; 文件夹统一去除结尾斜杠;
$files[0] = rtrim($files[0],'/');
$res = $this->modelSource->removeFromTag($files,$data['tagID']);
}
show_json(LNG('explorer.success'),true);
}
//添加文档到tag;
public function filesAddToTag(){
$data = Input::getArray(array(
"tagID" => array("check"=>"int"),
"files" => array("check"=>"require"),
));
$data['files'] = str_replace("__*@*__",',',$data['files']);
$files = explode(',',$data['files']);
if(!$files){
show_json(LNG('explorer.error'),false);
}
foreach ($files as $file) {
$res = $this->fileAddTag($file,$data['tagID']);
}
show_json(LNG('explorer.success'),true);
}
// 标签包含内容数量上限控制;
private function fileAddTag($file,$tagID){
$count = $this->modelSource->where(array('tagID'=>$tagID))->count();
if( $count > $GLOBALS['config']['systemOption']['tagContainMax'] ){
show_json(LNG("common.numberLimit"),false);
}
Action('explorer.listSafe')->authCheckAllow($file);
return $this->modelSource->addToTag($file,$tagID);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/tagGroup.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 部门公共标签处理
* get //部门标签获取 [参数]:groupID
* set //部门标签设置 [参数]:groupID,value
* filesRemoveFromTag //部门文件移除公共标签 [参数]:groupID,files,tagID
* filesAddToTag //部门文件添加公共标签 [参数]:groupID,files,tagID
*
* --------------
* tagAppendItem() //部门文档,追加公共标签信息;
* listSource() //根据部门标签筛选内容
*/
class explorerTagGroup extends Controller{
private $model;
function __construct(){
parent::__construct();
$this->model = Model('GroupTag');
$this->checkAuth();
}
/*
获取设置标签; 前后顺序即为排序关系
{group:[{name:xx,icon:xx}...] ,list:[{id:xx,name:xx},...], ...};// 标签分组,标签列表;
*/
public function get(){
$data = Input::getArray(array(
"groupID" => array("check"=>"int"),
));
$tagList = $this->groupTag($data['groupID']);
show_json($tagList);
}
// 标签数据写入; (groupTag:mysql-text字段; json 64k/100 =6千个)
// 标签设置检测: id不重复;名称不重复; 分组名称不同;
public function set(){
$data = Input::getArray(array(
'diff' => array("check"=>"json"),
"groupID" => array("check"=>"int"),
));
$dataLike = array(
'group' => array(array('_idKey_'=>'id','_autoID_'=>"number")),
'list' => array(array('_idKey_'=>'id','_autoID_'=>"number")),
);
$listData = $this->groupTag($data['groupID']);
$data['value'] = kodDiff::diffApply($listData,$data['diff'],$dataLike);
// 新建分组时处理;
foreach($data['value']['list'] as &$item){
if($item['_groupAddTemp']){
$group = array_find_by_field($data['value']['group'],'_groupAddTemp',$item['_groupAddTemp']);
if($group && $group['id']){$item['group'] = $group['id'];}
}
unset($item['_groupAddTemp']);
};unset($item);
foreach ($data['value']['group'] as &$item) {
unset($item['_groupAddTemp']);
};unset($item);
// pr($data['value'],$listData,$data['diff']);exit;
if(!$this->tagSetCheck($data['value'],$data['groupID'])){
show_json(LNG("common.invalidParam"),false);
}
Model('SystemLog')->addLog('explorer.tagGroup.set', $data);//操作日志记录;
$this->model->set($data['groupID'],$data['value']);
show_json($this->groupTag($data['groupID']),true);
}
// 标签设置检测: id不重复;名称不重复; 分组名称不同;
// 标签id有删除:前端强提醒, 清空该标签关联到的文档(tagID对应的文档-removeByTag);
private function tagSetCheck($listData,$groupID){
if(!is_array($listData) || !is_array($listData['list'])) return false;
$idList = array();$tagNameList = array();
foreach($listData['list'] as $tag){
if(!$tag['id']){return false;}
if(in_array($tag['id'],$idList)){return false;}
if(in_array($tag['name'],$tagNameList)){return false;}
$idList[] = $tag['id'];$tagNameList[] = $tag['name'];
}
// 标签有删除时; 则解除删除标签对文档的关联;
$beforeList = $this->groupTag($groupID);
foreach($beforeList['list'] as $tag){
if(in_array($tag['id'],$idList)) continue;
$this->model->removeByTag($groupID,$tag['id']);
}
return true;
}
// 部门子内容,公共标签追加; 根部门--追加 groupTagList
public function tagAppendItem(&$pathInfo){
if(!isset($pathInfo['targetType']) || isset($pathInfo['shareID'])) return $pathInfo;
if($pathInfo['targetType'] != 'group') return $pathInfo;
$groupID = $pathInfo['targetID'];
$groupTagInfo = $this->groupTagGet($groupID);
// 是否为部门管理员,继承当前文档权限( 下层权限小于上层权限, 使用下层权限)
if(is_array($pathInfo['auth']) && !AuthModel::authCheckRoot($pathInfo['auth']['auth'])){
$groupTagInfo['isGroupRoot'] = false;
}
$pathInfo['sourceInfo']['isGroupRoot'] = $groupTagInfo['isGroupRoot']; // 是否为该部门管理员
$pathInfo['sourceInfo']['isGroupHasTag'] = $groupTagInfo['isGroupHasTag']; // 是否有公共标签
// 部门根目录
if($pathInfo['parentID'] == '0'){
$pathInfo['sourceInfo']['groupTagList'] = $groupTagInfo;
}
// 部门子目录;关联标签; sourceInfo['groupTagInfo'];
$groupSource = $this->sourceTagList($groupID);
if(isset($groupSource[$pathInfo['sourceID']])){
$tags = $groupSource[$pathInfo['sourceID']];
$pathInfo['sourceInfo']['groupTagInfo'] = $this->getTags($groupID,$tags);
}
return $pathInfo;
}
private function groupTagGet($groupID){
static $list = array();
if(!isset($list[$groupID])){
$groupTag = $this->groupTag($groupID);
$groupTag['isGroupRoot'] = Action('filter.userGroup')->allowChangeGroup($groupID);
$groupTag['isGroupHasTag'] = isset($groupTag['list']) && count($groupTag['list']) > 0;
$list[$groupID] = $groupTag;
}
return $list[$groupID];
}
private function groupTag($groupID){
$listData = $this->model->get($groupID);//pr($listData);exit;
if($listData['_hasDiff']){return $listData;}
// 旧版数据处理兼容; 分组id,标签id自适应处理;
$listData['_hasDiff'] = true;unset($listData['idMax']);
if(!$listData['list'] ){$listData['list'] = array();}
if(!$listData['group']){$listData['group'] = array();}
kodDiff::arrayAutoID($listData['list']);
kodDiff::arrayAutoID($listData['group']);
foreach ($listData['list'] as $i => &$tag){
$tag['group'] = _get($listData['group'][$tag['group']],'id','1');
};unset($tag);
$this->model->set($groupID,$listData);
return $listData;
}
// 该部门下文档公共标签关联数据;
private function sourceTagList($groupID){
static $list = array();
if(!isset($list[$groupID])){
$arr = $this->model->listData($groupID);
$list[$groupID] = array_to_keyvalue_group($arr,'path','tagID');
}
return $list[$groupID];
}
private function getTags($groupID,$tags){
static $list = array();
if(!isset($list[$groupID])){
$arr = $this->groupTag($groupID);
$arr['listTag'] = array_to_keyvalue($arr['list'],'id');
$list[$groupID] = $arr;
}
$result = array();
$tagList = $list[$groupID];
if(!$tags || !$tagList || !$tagList['list']) return $result;
foreach($tags as $tagID){
$tagInfo = $tagList['listTag'][$tagID.''];
if(!$tagInfo) continue;
$tagInfo['groupInfo'] = array_find_by_field($tagList['group'],'id',$tagInfo['group']);
unset($tagInfo['group']);
$result[] = $tagInfo;
}
return $result;
}
// 根据$id获取部门筛选tag的文档列表;
public function listSource($groupID,$tags){
$tags = $tags[0] ? $tags : false;
$groupInfo = Model('Group')->getInfo($groupID);
$result = Model("GroupTag")->listSource($groupID,$tags);
$tagList = $this->getTags($groupID,$tags);
$tagName = $tags ? implode(',',array_to_keyvalue($tagList,'','name')) : '-';
$tagInfo = array('name'=>$tagName,'pathDesc'=>LNG('explorer.groupTag.pathDesc'));
$tagInfo['pathAddress'] = array(
array("name"=> $groupInfo['name'],"path"=>KodIO::make($groupInfo['sourceInfo']['sourceID'])),
array("name"=> LNG('common.tag').': '.$tagInfo['name'],"path"=>$this->in['path']),
);
if(!$result){$result = array("fileList"=>array(),'folderList'=>array());}
$tagInfo['sourceRoot'] = "groupPath";
$result['currentFieldAdd'] = $tagInfo;
$result['groupTagList'] = Model("GroupTag")->get($groupID);
return $result;
}
/**
* 权限检测;
* 部门公共标签编辑: 仅部门管理员有权限
* 文档标签设置: 对文档有编辑权限
*/
private function checkAuth(){
if(strtolower(MOD.'.'.ST) != 'explorer.taggroup') return;
$ACTION = strtolower(ACT);
$checkSourceAuth = array('filesRemoveFromTag','filesAddToTag');
// 文档权限检测;
$groupID = $this->in['groupID'];
foreach($checkSourceAuth as $action){
if($ACTION != strtolower($action)) continue;
$files = explode(',',$this->in['files']);
foreach($files as $file){
$path = KodIO::make($file);
if(!Action('explorer.auth')->fileCanWrite($path)){
show_json(LNG('explorer.noPermissionAction'),false);
}
$pathInfo = IO::info($path);
if($pathInfo['targetType'] != 'group' || $pathInfo['targetID'] != $groupID){
show_json(LNG('common.notExists'),false);
}
}
return;
}
}
//======== tag关联资源管理 =========
//将文档从某个tag中移除
public function filesRemoveFromTag(){
$data = Input::getArray(array(
"tagID" => array("check"=>"int"),
"files" => array("check"=>"require"),
"groupID" => array("check"=>"int"),
));
$files = explode(',',$data['files']);
if(!$files){show_json(LNG('explorer.error'),false);}
$res = $this->model->removeFromTag($data['groupID'],$files,$data['tagID']);
show_json($res? LNG('explorer.success'): LNG('explorer.error'),!!$res);
}
//添加文档到tag;
public function filesAddToTag(){
$data = Input::getArray(array(
"tagID" => array("check"=>"int"),
"files" => array("check"=>"require"),
"groupID" => array("check"=>"int"),
));
$files = explode(',',$data['files']);
if(!$files){show_json(LNG('explorer.error'),false);}
foreach ($files as $file) {
$res = $this->model->addToTag($data['groupID'],$file,$data['tagID']);
}
show_json(LNG('explorer.success'),true);
}
// 前后顺序即为排序关系; 标签组包含子标签
public function testData(){
$listData = array(
'group' => array(
array('name'=>'用户规模','icon'=>'ri-user-line'),
array('name'=>'客户分类','icon'=>'ri-profile-line'),
array('name'=>'所属行业','icon'=>'ri-building-line'),
array('name'=>'项目状态','icon'=>'ri-money-cny-circle-line'),
),
'list' => array(
array('id'=>1,'name'=>'<50','group'=>'0'),
array('id'=>2,'name'=>'50~100','group'=>'0'),
array('id'=>3,'name'=>'100~300','group'=>'0'),
array('id'=>4,'name'=>'300~500','group'=>'0'),
array('id'=>5,'name'=>'500~1000','group'=>'0'),
array('id'=>6,'name'=>'1000~3000','group'=>'0'),
array('id'=>7,'name'=>'>3000','group'=>'0'),
array('id'=>8,'name'=>'个人采购','group'=>'1'),
array('id'=>9,'name'=>'企业采购','group'=>'1'),
array('id'=>10,'name'=>'第三方','group'=>'1'),
array('id'=>11,'name'=>'合作伙伴','group'=>'1'),
array('id'=>12,'name'=>'金融保险','group'=>'2'),
array('id'=>13,'name'=>'IT互联网','group'=>'2'),
array('id'=>14,'name'=>'能源行业','group'=>'2'),
array('id'=>15,'name'=>'学校教育','group'=>'2'),
array('id'=>16,'name'=>'政府单位','group'=>'2'),
array('id'=>17,'name'=>'房地产','group'=>'2'),
array('id'=>18,'name'=>'跟进中','group'=>'3'),
array('id'=>19,'name'=>'成单-已付款','group'=>'3'),
array('id'=>20,'name'=>'未成单-已终止','group'=>'3'),
)
);
return $listData;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/upload.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerUpload extends Controller{
public function __construct(){
parent::__construct();
$this->model = Model("Source");
}
public function pathAllowReplace($path){
$notAllow = array('\\', ':', '*', '?', '"', '<', '>', '|',"\r","\n");//不允许字符
$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);
}
return str_replace($notAllow,'_',$path);
}
// 通过上传内容获得上传临时文件;(插件;文件编辑保存)
public function fileUploadTemp(){
$this->in["chunkSize"] = '0';
$this->in["size"] = '0';
$uploader = new Uploader();
$localFile = $uploader->upload();
$uploader->statusSet(false);
return $localFile;
}
/**
* 上传,三个阶段
* checkMd5:上传前;秒传处理、前端上传处理
* uploadLinkSuccess: 前端上传完成处理;
* 其他: 正常通过后端上传上传到后端;
*/
public function fileUpload(){
$this->authorizeCheck();
$uploader = new Uploader();
$savePath = $this->in['path'];
if(!IO::exist($savePath)) show_json(LNG('explorer.upload.errorPath'),false);
if( $this->in['fullPath']){//带文件夹的上传
$fullPath = KodIO::clear($this->in['fullPath']);
$fullPath = $this->pathAllowReplace($fullPath);
$fullPath = get_path_father($fullPath);
$savePath = IO::mkdir(rtrim($savePath,'/').'/'.$fullPath);
}
$repeat = Model('UserOption')->get('fileRepeat');
$repeat = isset($this->in['fileRepeat']) ? $this->in['fileRepeat'] : $repeat;
$repeat = isset($this->in['repeatType']) ? $this->in['repeatType'] : $repeat; // 向下兼容pc客户端
// 上传前同名文件处理(默认覆盖; [覆盖,重命名,跳过])
$uploader->fileName = $this->pathAllowReplace($uploader->fileName);
if($repeat == REPEAT_RENAME){
$uploader->fileName = IO::fileNameAuto($savePath,$uploader->fileName,$repeat);
if(!$uploader->fileName){show_json('skiped',true);}
}
$savePath = rtrim($savePath,'/').'/'.$uploader->fileName;
// 文件保存; 必须已经先存在;
if($this->in['fileSave'] == '1'){
$repeat = REPEAT_REPLACE;
$info = IO::info($this->in['path']);
if(!$info){
show_json(LNG("common.pathNotExists"),false);
}
$this->in['name'] = $info['name'];
$uploader->fileName = $this->pathAllowReplace($info['name']);
$parent = IO::pathFather($info['path']);
if(!$parent){show_json(LNG("common.pathNotExists"),false);}
$savePath = rtrim($parent,'/').'/'.$info['name'];// 重新构造路径 父目录+文件名;
}
// 第三方存储上传完成
if( isset($this->in['uploadLinkSuccess']) ){
$this->fileUploadByClient($savePath,$repeat);
}
if( isset($this->in['checkType']) ){
$this->fileUploadCheckExist($uploader,$savePath,$repeat);
}
// 通过服务器上传;
$localFile = $uploader->upload();
$path = IO::upload($savePath,$localFile,true,$repeat);//本地到本地则用move的方式;
$uploader->clearData();//清空上传临时文件;
// pr($localFile,$path,$savePath,$uploader,$this->in);exit;
if($path){
show_json(LNG("explorer.upload.success"),true,$this->uploadInfo($path));
}else{
show_json(IO::getLastError(LNG("explorer.upload.error")),false);
}
}
private function uploadInfo($path){
$info = IO::info($path);
// 记录文件本身最后修改时间;
if($info && $this->in['modifyTime']){
$modifyTime = abs(intval(substr($this->in['modifyTime'],0,10)));
if($modifyTime > 1000 && $modifyTime < time()){
IO::setModifyTime($path,$modifyTime);
}
}
if($this->in['fileInfo'] != '1') return $path;
$info = array_field_key($info,array("ext",'name','createTime','size','path','pathDisplay'));
$info['downloadPath'] = Action('explorer.share')->link($path);
return $info;
}
// 第三方上传获取凭证
private function authorizeCheck(){
if( !isset($this->in['authorize']) ) return;
$inPath = $this->in['path'];
if(substr(IO::getType($inPath), 0, 2) == 'db'){
$ioFileDriver = KodIO::ioFileDriverGet($inPath);
$path = '{io:'.$ioFileDriver['id'].'}/'.$inPath;
}else{
$pathBase = substr($inPath, 0, stripos($inPath, '/'));
$path = (!$pathBase ? $inPath : $pathBase) . '/' . $inPath;
}
$paramMore = $this->getParamMore();
$result = IO::uploadMultiAuth($path, $paramMore);
show_json($result, true);
}
// 获取paramMore,兼容json和数组
private function getParamMore(){
if(!isset($this->in['paramMore'])) return array();
$paramMore = $this->in['paramMore'];
if (!is_array($paramMore)) {
$paramMore = json_decode($paramMore, true);
if (!$paramMore) return array();
}
// 兼容旧版 ext:?partNumber=1&uploadId=xxx
if (!empty($paramMore['ext'])) {
$query = parse_url_query($paramMore['ext']);
if (is_array($query)) $paramMore = array_merge($paramMore, $query); // partNumber, uploadId
// unset($paramMore['ext']);
}
return $paramMore;
}
//秒传及断点续传处理
private function fileUploadCheckExist($uploader,$savePath,$repeat){
$size = $this->in['size'];
$isSource = false;
$hashSimple = isset($this->in['checkHashSimple']) ? $this->in['checkHashSimple']:false;
$hashMd5 = isset($this->in['checkHashMd5']) ? $this->in['checkHashMd5']:false;
if(substr(IO::getType($savePath), 0, 2) == 'db' && $hashSimple ){
$isSource = true;
$file = Model("File")->findByHash($hashSimple,$hashMd5);
}else{
$file = array('hashSimple' => null, 'hashMd5' => null); // 非绑定数据库存储不检查秒传
}
if(!$file['hashMd5']){$file['hashSimple'] = null;}
$checkChunkArray = array();
if($hashSimple){$checkChunkArray = $uploader->checkChunk();} // 断点续传保持处理;
$ioFileDriver = KodIO::ioFileDriverGet($savePath);
$infoData = array(
"checkChunkArray" => $checkChunkArray,
"checkFileHash" => array(
"hashSimple"=>$file['hashSimple'],
"hashMd5" =>$file['hashMd5']
),
"uploadLinkInfo" => IO::uploadLink($savePath, $size),//前端上传信息获取;
"uploadToKod" => $isSource,
"uploadChunkSize" => $this->config['settings']['upload']['chunkSize'],
"kodDriverType" => $ioFileDriver['driver'],
);
$linkInfo = &$infoData['uploadLinkInfo'];
// trace_log(['fileUploadCheckExist',$savePath,$linkInfo,$ioFileDriver['name'].':'.$ioFileDriver['name']]);
if(isset($linkInfo['host'])){ // 前端上传时,自适应处理(避免http,https混合时浏览器拦截问题; )
$linkInfo['host'] = str_replace("http://",'//',$linkInfo['host']);
// $linkInfo['host'] = str_replace("https://",'//',$linkInfo['host']); // 存储只限https访问时去掉会有异常
}
$this->checkAllowUploadWeb($infoData);
// 保留参数部分; kod挂载kod的webdav前端上传;
if($this->in['addUploadParam']){$infoData['addUploadParam'] = $this->in['addUploadParam'];} // server;
if($linkInfo['webdavUploadTo']){$infoData = $linkInfo;} // webdav client 首次检测中转访问;
if( $this->in['checkType'] == 'matchMd5' &&
!empty($this->in['checkHashMd5']) &&
!empty($file['hashMd5']) &&
$this->in['checkHashMd5'] == $file['hashMd5']
){
$path = IO::uploadFileByID($savePath,$file['fileID'],$repeat);
$uploader->clearData();//清空上传临时文件;
show_json(LNG('explorer.upload.secPassSuccess'),true,$this->uploadInfo($path));
}else{
show_json(LNG('explorer.success'),true,$infoData);
}
}
// 检测, 是否允许前端对象存储直传(腾讯cos+Android浏览器form分片上传时,)
private function checkAllowUploadWeb(&$infoData){
if(!$infoData['uploadLinkInfo']){return;}
// if(stristr($_SERVER['HTTP_USER_AGENT'],'android')){$infoData['uploadLinkInfo'] = false;}
}
/**
* 前端上传,完成后记录并处理;
*
* $key是完整路径,type为DB(即为默认io)时,$savePath={source:x}/$key,
* 获取默认io判断:{io:n}/$key
* 否则,$savePath={io:x}/$key,直接判断
*/
private function fileUploadByClient($savePath,$repeat){
$paramMore = $this->getParamMore();
$remotePath = $this->parsePath(KodIO::ioFileDriverGet($savePath),$this->in['key']);
// 耗时操作;
if(!IO::isFile($remotePath)){
show_json(LNG("explorer.upload.error"), false);
}
$path = IO::addFileByRemote($savePath, $remotePath,$paramMore,$this->in['name'],$repeat);
show_json(LNG("explorer.upload.success"),true,$this->uploadInfo($path));
}
private function parsePath($driver,$path){
$bucket = isset($driver['config']['bucket']) ? $driver['config']['bucket'].'/':'';
$pathBase = trim($driver['config']['basePath'], '/');
$pathPre = $bucket.$pathBase;
if(substr($path,0,strlen($pathPre)) == $pathPre){
$path = substr($path,strlen($pathPre));
}else if(!empty($pathBase) && substr($path,0,strlen($pathBase)) == $pathBase){
$path = substr($path,strlen($pathBase));
}
$remotePath = '{io:'.$driver['id'].'}/'.trim($path, '/');
return $remotePath;
}
// 远程下载
public function serverDownload() {
if(!$this->in['uuid']){
$this->in['uuid'] = md5($this->in['url']);
}
$uuid = 'download_'.$this->in['uuid'];
$this->serverDownloadCheck($uuid);
$url = $this->in['url'];
$savePath = rtrim($this->in['path'],'/').'/';
$header = url_header($url);
if (!$header){
show_json(LNG('download_error_exists'),false);
}
$filename = _get($this->in,'name',$header['name']);
$filename = unzip_filter_ext($filename);
$tempFile = TEMP_FILES.md5($uuid);
mk_dir(TEMP_FILES);
Session::set($uuid,array(
'supportRange' => $header['supportRange'],
'length' => $header['length'],
'path' => $tempFile,
'name' => $filename,
));
$this->serverDownloadHashCheck($url,$header,$savePath,$filename,$uuid);
$result = Downloader::start($url,$tempFile);
if($result['code']){
$outPath = IO::copy($tempFile,$savePath,REPEAT_RENAME,$filename);
show_json(LNG('explorer.downloaded'),true,IO::info($outPath));
}else{
show_json($result['data'],false);
}
}
/**
* 远程下载秒传处理;
* 小于10M的文件不处理;
*/
private function serverDownloadHashCheck($url,$header,$savePath,$filename,$uuid){
return;// 暂时关闭该特性;
if($header['length'] < 10 * 1024*1024) return false;
$driver = new PathDriverUrl();
$fileHash = $driver->hashSimple($url,$header); // 50个请求;8s左右;
$file = Model("File")->findByHash($fileHash);
if(!$fileHash || !$file) return;
$tempFile = $file['path'];
Session::remove($uuid);
$outPath = IO::copy($tempFile,$savePath,REPEAT_RENAME);
$fileName= IO::fileNameAuto($savePath,$filename,REPEAT_RENAME);
$outPath = IO::rename($outPath,$fileName);
show_json(LNG('explorer.upload.secPassSuccess'),true,IO::info($outPath));
}
private function serverDownloadCheck($uuid){
$data = Session::get($uuid);
if ($this->in['type'] == 'percent') {
if (!$data) show_json('uuid error',false);
$result = array(
'supportRange' => $data['supportRange'],
'uuid' => $this->in['uuid'],
'length' => intval($data['length']),
'name' => $data['name'],
'size' => intval(@filesize($data['path'].'.downloading')),
'time' => mtime()
);
show_json($result);
}else if($this->in['type'] == 'remove'){//取消下载;文件被删掉则自动停止
if($data){
IO::remove($data['path'].'.downloading');
IO::remove($data['path'].'.download.cfg');
Session::remove($uuid);
}
show_json('');
}
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/userShare.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerUserShare extends Controller{
private $model;
function __construct(){
parent::__construct();
$this->model = Model('Share');
}
// 通过文档获取分享;没有则返回false;
public function get(){
$path = Input::get('path','require');
$pathParse = KodIO::parse($path);$shareInfo = false;
if($pathParse['type'] == KodIO::KOD_SHARE_ITEM){
show_json($this->getShareInfo($pathParse['id']));
}
// 物理路径,io路径;
if( $pathParse['type'] == KodIO::KOD_IO || !$pathParse['type'] ){
$shareInfo = $this->model->getInfoBySourcePath(rtrim($path,'/'));
}else{
$sourceID = KodIO::sourceID($path);
$shareInfo = $this->model->getInfoByPath($sourceID);
}
if($shareInfo && $shareInfo['userID'] != KodUser::id()){
show_json(LNG('explorer.noPermissionAction'),false);
}
$shareInfo = Action('explorer.shareOut')->sendShareSiteAppend($shareInfo);
show_json($shareInfo);
}
// 内部协作分享,分享对象角色权限为拥有者时,可以编辑该协作分享(成员及权限/过期时间)
private function getShareInfo($shareID,$checkAuth = true){
$shareInfo = $this->model->getInfo($shareID);
if(!$shareInfo){show_json(LNG('explorer.noPermissionAction'),false);}
if($shareInfo['userID'] == KodUser::id()){return $shareInfo;}
$sourceInfo = $this->sharePathInfo($shareID);
if( !$sourceInfo || !$sourceInfo['auth'] ||
!Model('Auth')->authCheckRoot($sourceInfo['auth']['authValue']) ){
if($checkAuth){ // 编辑后不检测权限(与我协作-管理者,移除或降低自己的权限)
return show_json(LNG('explorer.noPermissionAction'),false);
}
}
$shareInfo['selfIsShareToUser'] = true;
$shareInfo['sourceInfo'] = $sourceInfo;
return $shareInfo;
}
// 分享信息处理;
public function shareAppendItem(&$item){
$shareInfo = _get($item,'shareInfo');
if(!isset($item['sourceInfo'])){$item['sourceInfo'] = array();}
if(isset($item['sourceInfo']['shareInfo']) ) return $item;
static $shareList = false;
if($shareList === false){
$shareList = $this->model->listSimple();
$shareList = array_to_keyvalue($shareList,'sourcePath');
}
$shareInfo = $shareInfo ? $shareInfo : _get($shareList,$item['path']);
$shareInfo = $shareInfo ? $shareInfo : _get($shareList,rtrim($item['path'],'/'));
$shareInfo = $shareInfo ? $shareInfo : _get($shareList,rtrim($item['path'],'/').'/');
if(!$shareInfo) return $item;
$item['sourceInfo']['shareInfo'] = Model("Source")->shareFilterShow($shareInfo);
return $item;
}
/**
* 我的分享列表
* 点击进入对应文档目录;
* link/to
*/
public function myShare($type=''){
$shareList = $this->model->listData($type);
$result = array('fileList'=>array(),'folderList'=>array(),'pageInfo'=>$shareList['pageInfo']);
$sourceArray = array_to_keyvalue($shareList['list'],'','sourceID');
$sourceArray = array_unique($sourceArray);
if($sourceArray){
$where = array(
'sourceID' => array('in',$sourceArray),
'isDelete' => 0,
);
$sourceList = Model('Source')->listSource($where);
$sourceArray = array_merge($sourceList['folderList'],$sourceList['fileList']);
$sourceArray = array_to_keyvalue($sourceArray,'sourceID');
}
$notExist = array();
$sourceCountGroup = 0;$sourceCountIO = 0;
foreach ($shareList['list'] as $shareItem) {
$shareItem = Model("Source")->shareFilterShow($shareItem);
if($shareItem['sourceID'] == '0'){// IO 对象存储等加速;
$info = $this->sharePathInfoCheck($shareItem['sourcePath'],$shareItem);
}else{
$info = $sourceArray[$shareItem['sourceID']];
}
if(!$info){
$notExist[] = $shareItem['shareID'];
continue;
}
$info['sharePath'] = KodIO::makeShare($shareItem['shareID'],$info['sourceID']);
$info['shareInfo'] = $shareItem;
$key = $info['type'] == 'folder' ? 'folderList':'fileList';
$this->shareTarget($info,$shareItem);
// 协作内容不再有分享权限时处理; 其他人内容--隐藏; 自己的内容-突出显示;(前提:自己有内部协作或外链分享的对应角色权限);
$shareType = $type == 'to' ? 'shareTo':'shareLink';
$authType = $shareType == 'shareTo' ? 'explorer.share':'explorer.shareLink';
if( Action('user.authRole')->authCan($authType) &&
!Action('explorer.authUser')->canShare($shareItem)){
$this->removeShare($shareItem,$shareType);continue;
}
$result[$key][] = $info;
if(!$info['sourceID']){$sourceCountIO++;}
if($info['groupParentLevel']){$sourceCountGroup++;}
}
// if($notExist){$this->model->remove($notExist);}// 自动清除不存在的分享内容;
// 对自己和部门内容进行分组;
$groupShow = array(
'selfData' => array(
'type' => 'selfData',
'title' => LNG('explorer.pathGroup.shareSelf'),
"filter"=> array('groupParentLevel'=>'_null_','sourceID'=>'')
),
'groupData' => array(
'type' => 'groupData',
'title' => LNG('explorer.pathGroup.shareGroup'),
"filter"=> array('groupParentLevel'=>'','sourceID'=>'')
),
'ioData' => array(
'type' => 'ioData',
'title' => LNG('admin.storage.localStore').'/IO',
"filter"=> array('sourceID'=>'_null_')
),
);
$length = count($result['folderList']) + count($result['fileList']);
if($sourceCountGroup == 0){unset($groupShow['groupData']);}
if($sourceCountIO == 0){unset($groupShow['ioData']);}
if($length <= 3 || count($groupShow) <= 1){$groupShow = array();}
if($groupShow){$result['groupShow'] = array_values($groupShow);}
return $result;
}
private function sharePathInfoCheck($path,$shareItem){
$parse = KodIO::parse($path);
if ($parse['driverType'] == 'io') {
$driver = Model('Storage')->listData($parse['id']);
if (!$driver) return false;
$type = strtolower($driver['driver']);
$typeList = $GLOBALS['config']['settings']['ioClassList'];
$class = 'PathDriver'.(isset($typeList[$type]) ? $typeList[$type] : ucfirst($type));
if( !class_exists($class) ) return false;
}
// 外部联合分享;
if($shareItem['isLink'] == '0' && _get($shareItem,'options.site')){
$path = '{shareItemOut:'.$shareItem['shareID'].'}/';
}
try {
$info = IO::info($path);
} catch (Exception $e){$info = false;}
return $info;
}
public function shareToMe($type=''){
$allowTree = Model("SystemOption")->get('shareToMeAllowTree');
$showType = Model('UserOption')->get('shareToMeShowType');
if($allowTree == '0'){$showType = 'list';}
if( $showType == 'group' || strpos($type, 'group') === 0){
return Action('explorer.userShareGroup')->get($type);
}
if( $showType == 'user' || strpos($type, 'user') === 0 ){
return Action('explorer.userShareUser')->get($type);
}
Model("share_to")->selectPageReset();// 确保被筛选后分页数据正常;
$shareList = $this->model->listToMe(5000);
Model("share_to")->selectPageRestore();
$shareHide = Model('UserOption')->get('hideList','shareToMe');
$shareHide = $shareHide ? json_decode($shareHide,true):array();
foreach ($shareList['list'] as $key=>$shareItem){
if(isset($shareHide[$shareItem['shareID'].''])){
$shareItem['shareHide'] = 1;
}else{
$shareItem['shareHide'] = 0;
}
$shareList['list'][$key] = $shareItem;
//$type: '':显示内容; hide: 隐藏内容; all: 全部内容;
if($type == '' && $shareItem['shareHide']){$shareList['list'][$key] = false;}
if($type == 'hide' && !$shareItem['shareHide']){$shareList['list'][$key] = false;}
}
$result = $this->shareToMeListMake($shareList['list']);
$result['currentFieldAdd'] = array("pathDesc"=>'['.LNG('admin.setting.shareToMeList').'],'.LNG('explorer.pathDesc.shareToMe'));
return $result;
}
public function shareToMeListMake($shareList){
$result = array('fileList'=>array(),'folderList'=>array());
$sourceArray = array_to_keyvalue($shareList,'','sourceID');
$sourceArray = array_unique($sourceArray);
if($sourceArray){
$where = array(
'sourceID' => array('in',$sourceArray),
'isDelete' => 0,
);
Model('Source')->selectPageReset();
$sourceList = Model('Source')->listSource($where);
Model('Source')->selectPageRestore();
$sourceArray = array_merge($sourceList['folderList'],$sourceList['fileList']);
$sourceArray = array_to_keyvalue($sourceArray,'sourceID');
}
$notExist = array();
foreach($shareList as $shareItem) {
if(!$shareItem) continue;
$timeout = intval(_get($shareItem,'options.shareToTimeout',0));
if($timeout > 0 && $timeout < time()) continue;// 过期内容;
if($shareItem['sourceID'] == '0'){// 物理路径,io路径;
$info = $this->sharePathInfoCheck($shareItem['sourcePath'],$shareItem);
}else{
$info = $sourceArray[$shareItem['sourceID']];
}
if(!$info){
$notExist[] = $shareItem['shareID'];
continue;
}
$info = $this->_shareItemeParse($info,$shareItem);
if(!$info) continue;
if(_get($info,'shareUser.userID') == '0'){$info['isFromSystem'] = '1';} // 系统分享标记;
$key = $info['type'] == 'folder' ? 'folderList':'fileList';
if(isset($shareItem['shareHide'])){$info['shareHide'] = $shareItem['shareHide'];}
$result[$key][] = $info;
}
// 对自己和部门内容进行分组;
$groupShow = array(
'userData' => array(
'type' => 'userData',
'title' => LNG('explorer.toolbar.shareToMe'),
"filter"=> array('shareID'=>'','isFromSystem'=>'_null_','isShareOut'=>'_null_')
),
'systemData' => array(
'type' => 'systemData',
'title' => LNG('explorer.share.shareSystem'),'desc' => LNG('explorer.share.shareSystemDesc'),
"filter"=> array('isFromSystem'=>'','isShareOut'=>'_null_')
),
'outerData' => array(
'type' => 'outerData',
'title' => LNG('explorer.shareOut.titlePath'),"desc"=>LNG('explorer.shareOut.titlePathDesc'),
"filter"=> array('isShareOut'=>'')
),
);
$length = count($result['folderList']) + count($result['fileList']);
if($length <= 3){$groupShow = array();}
if($groupShow){$result['groupShow'] = array_values($groupShow);}
// if($notExist){$this->model->remove($notExist);} // 自动清除不存在的分享内容;
return $result;
}
public function shareDisplay(){
$data = Input::getArray(array(
"shareArr" => array("check"=>"json","default"=>array()),
"isHide" => array("check"=>"bool","default"=>'1'),
));
$shareHide = Model('UserOption')->get('hideList','shareToMe');
$shareHide = $shareHide ? json_decode($shareHide,true):array();
foreach ($data['shareArr'] as $shareID) {
$shareID = $shareID.'';
if($data['isHide'] == '1'){
$shareHide[$shareID] = '1';
}else{
unset($shareHide[$shareID]);
}
}
Model('UserOption')->set('hideList',json_encode($shareHide),'shareToMe');
show_json(LNG('explorer.success'),true);
}
// 自己退出当前分享 (所有协作成员都为用户,且成员包含自己时--可退出;)
public function shareExit(){
$data = Input::getArray(array(
"shareArr" => array("check"=>"json","default"=>array()),
));
$isRoot = KodUser::isRoot();
$errorArr = array();
foreach($data['shareArr'] as $shareID){
$shareInfo = $this->model->getInfo($shareID);
if( !$shareInfo || _get($shareInfo,'isShareTo') != '1' ||
!is_array($shareInfo['authList'])){
$errorArr[] = LNG('explorer.share.notExist');
continue;
}
$allUser = true;$hasSelf = false;$selfIndex = 0;
$authListNew = array();
foreach($shareInfo['authList'] as $i => $item){
$isUser = $item['targetType'] == SourceModel::TYPE_USER;
if(!$isUser){$allUser = false;}
if($isUser && $item['targetID'] == KodUser::id()){
$hasSelf = true;$selfIndex = $i;
}else{
$authListNew[] = $item;
}
}
// if(!$allUser){$errorArr[] = "share target all must be [user]";continue;}
if(!$hasSelf){$errorArr[] = "share target not include you";continue;}
$shareOptions = is_array($shareInfo['options']) ? $shareInfo['options']:array();
if($shareOptions['site']){
$shareTarget = _get($shareOptions,'shareTarget',array());
$shareTargetNew = array();$userSecret = '';
foreach($shareTarget as $i => $userItem){
if($i == $selfIndex){$userSecret = $userItem['secret'];}
if($i != $selfIndex){$shareTargetNew[] = $userItem;}
}
$res = Action("explorer.shareOut")->shareUserExit($shareOptions['site'],$shareOptions['shareID'],$userSecret);
if(is_array($res) && $res['info'] == 'kodbox'){
if(!$res['code']){$errorArr[] = $res['data'];}
}
$shareOptions['shareTarget'] = $shareTargetNew;
}
if(!$authListNew && $shareInfo['isLink'] == '0'){
$this->model->remove($shareID);
}else{
$this->model->shareEdit($shareID,array('isShareTo'=>'1','authTo'=>$authListNew,'options'=>$shareOptions));
}
}
$code = count($errorArr) > 0 ? false:true;
$msg = $code ? LNG('explorer.success') : implode(',',$errorArr);
show_json($msg,$code);
}
// 分享内容属性; 默认$sourceID为空则分享本身属性; 指定则文件夹字内容属性;
public function sharePathInfo($shareID,$sourceID=false,$withChildren=false){
$shareInfo = $this->model->getInfo($shareID);
if($shareInfo['sourceID'] == '0'){
$truePath = KodIO::clear($shareInfo['sourcePath'].$sourceID);
// $sourceInfo = IO::info($truePath);
$sourceInfo = array('path'=>$truePath);
}else{
$sourceID = $sourceID ? $sourceID : $shareInfo['sourceID'];
if(!$withChildren){
$sourceInfo = Model('Source')->pathInfo($sourceID);
}else{
$sourceInfo = Model('Source')->pathInfoMore($sourceID);
}
}
// pr($sourceID,$truePath,$sourceInfo,$shareInfo);exit;
if(!$this->shareIncludeCheck($shareInfo,$sourceInfo)) return false;
$sourceInfo = $this->_shareItemeParse($sourceInfo,$shareInfo);
return $sourceInfo;
}
// 检测附带文档是否归属于该分享;
private function shareIncludeCheck($shareInfo,$sourceInfo){
// pr_trace($shareInfo,$sourceInfo);exit;
if(!$shareInfo || !$sourceInfo) return false;
// 物理路径,io路径;
if($shareInfo['sourceID'] == '0'){
$sharePath = KodIO::clear($shareInfo['sourcePath']);
$thisPath = KodIO::clear($sourceInfo['path']);
if(substr($thisPath,0,strlen($sharePath)) != $sharePath) return false;
return true;
}
$shareSource = $shareInfo['sourceInfo'];
// 分享目标为文件,追加子内容必须是自己;
if( $shareSource['type'] == 'file' &&
$shareSource['sourceID'] != $sourceInfo['sourceID']){
return false;
}
if( $shareSource['type'] == 'folder' &&
strpos($sourceInfo['parentLevel'],$shareSource['parentLevel']) !== 0 ){
return false;
}
return true;
}
public function sharePathList($parseInfo){
$shareID = $parseInfo['id'];
$param = explode('/',trim($parseInfo['param'],'/'));
$shareInfo = $this->model->getInfo($shareID);
// 物理路径,io路径;
if($shareInfo['sourceID'] == '0'){
$truePath = KodIO::clear($shareInfo['sourcePath'].$parseInfo['param']);
$sourceInfo = $this->sharePathInfoCheck($truePath,$shareInfo);
if(!$sourceInfo) return false;
$list = IO::listPath($truePath);
}else{
$sourceID = $param[0] ? $param[0] : $shareInfo['sourceID'];
$sourceInfo = Model('Source')->pathInfo($sourceID);
if(!$this->shareIncludeCheck($shareInfo,$sourceInfo)) return false;
$list = Model('Source')->listSource(array('parentID' => $sourceID));
}
foreach ($list as $key => &$keyList) {
if($key != 'folderList' && $key != 'fileList' ) continue;
foreach ($keyList as &$source) {
$source = $this->_shareItemeParse($source,$shareInfo);
};unset($source);
};unset($keyList);
$list['current'] = $this->_shareItemeParse($sourceInfo,$shareInfo);
// pr($parseInfo,$truePath,$sourceInfo,$shareInfo,$list);exit;
return $list;
}
/**
* 处理source到分享列表
* 去除无关字段;处理parentLevel,pathDisplay
*/
public function _shareItemeParse($source,$share){
if(!$source || !is_array($source)){return false;}
$share = Model("Source")->shareFilterShow($share);
$sourceBefore = $source;
$user = Model('User')->getInfoSimpleOuter($share['userID']);
$source['auth'] = Model("SourceAuth")->authMake($share['authList']);//覆盖原来文档权限;每次进行计算
$source['shareCreateTime'] = $share['createTime'];
$source['shareModifyTime'] = $share['modifyTime'];
$source['shareID'] = $share['shareID'];
if($source['isShareOut']){return $source;}
$sourceRoot = isset($share['sourceInfo']) ? $share['sourceInfo'] : $source;
$source['shareUser'] = $user;
// 物理路径,io路径;
$pathAdd = $source['sourceID'];
if($share['sourceID'] == '0'){
$sharePath = KodIO::clear($share['sourcePath']);
$thisPath = KodIO::clear($source['path']);
$pathAdd = substr($thisPath,strlen($sharePath));
if(substr($thisPath,0,strlen($sharePath)) != $sharePath) return false;
// 子目录不再追加;
if($pathAdd){unset($source['shareInfo']);}
}
$source['path'] = KodIO::makeShare($share['shareID'],$pathAdd);
$source['path'] = KodIO::clear($source['path']);
if($source['auth'] && $share['sourceID'] != '0'){
$listData = array($source);
Model('Source')->_listAppendAuthSecret($listData);
$source = $listData[0];
if($share['userID'] == USER_ID){
$source['auth'] = $share['sourceInfo']['auth'];
}
}
// 分享者名字;
$userName = $user['nickName'] ? $user['nickName']:$user['name'];
$displayUser = '['.$userName.']'.LNG('common.share').'-'.$sourceRoot['name'];
if(!$user || $user['userID'] == '0'){$displayUser = $sourceRoot['name'];}
if($share['userID'] == USER_ID){
$displayUser = $sourceRoot['name'];
$shareInfoAdd = Model("Source")->shareFilterShow($share);
$source['sourceInfo']['selfShareInfo'] = array_merge($sourceRoot,$shareInfoAdd);
if(!$pathAdd){$source['sourceInfo']['shareInfo'] = $share;}
}
if($sourceRoot['targetType'] == 'group'){
$source['sharePathFrom'] = $sourceRoot['pathDisplay'];
}else{
$source['sharePathFrom'] = LNG('explorer.toolbar.rootPath').'('.$userName.')';
}
$source['parentLevel'] = ',0,'.substr($source['parentLevel'],strlen($sourceRoot['parentLevel']));
$sourceNameArr = explode('/',trim($source['pathDisplay'],'/'));
$sourceRootNameArr = explode('/',trim($sourceRoot['pathDisplay'],'/'));
// 通过目录层级截取;避免类似于根目录name不一致的情况;
$source['pathDisplay'] = $displayUser.'/'.implode('/',array_slice($sourceNameArr,count($sourceRootNameArr)));
//$source['pathDisplay'] = $displayUser.'/'.substr($source['pathDisplay'],strlen($sourceRoot['pathDisplay']));
if($share['sourceID'] == '0'){
$source['parentLevel'] = '';
$source['pathDisplay'] = $displayUser.'/'.$pathAdd;
}
$source['pathDisplay'] = KodIO::clear($source['pathDisplay']);
if($source['type'] == 'folder'){
$source['pathDisplay'] = rtrim($source['pathDisplay'],'/').'/';
}
// 读写权限;
if($source['auth']){// 读写权限同时受: 来源权限+设置权限;
$isWriteable = true;$isReadable = true;
if($share['sourceID'] == '0'){ // 物理路径协作分享,保留原来权限;
$isWriteable = array_key_exists('isWriteable',$source) ? $source['isWriteable'] : true;
$isReadable = array_key_exists('isReadable',$source) ? $source['isReadable'] : true;
}
// 物理路径分享,自己访问自己分享的内容时权限处理;
if($share['sourceID'] == '0' && $share['userID'] == USER_ID){
$source['auth']['authValue'] = AuthModel::authAll();
}
$source['isWriteable'] = $isWriteable && AuthModel::authCheckEdit($source['auth']['authValue']);
$source['isReadable'] = $isReadable && AuthModel::authCheckView($source['auth']['authValue']);
}
if(isset($source['sourceInfo']['tagInfo'])){
unset($source['sourceInfo']['tagInfo']);
}
$this->shareTarget($source,$share);
// 协作内容不再有分享权限时处理; 其他人内容--隐藏; 自己的内容-突出显示;
if(!Action('explorer.authUser')->canShare($share)){return false;}
// pr($source,$sourceBefore,$share);exit;
return $source;
}
private function shareTarget(&$source,$share){
$isRoot = false;
if($source['sourceID'] && $source['sourceID'] == $share['sourceID']){$isRoot = true;}
if($share['sourcePath'] && count(explode('/',trim($source['path'],'/'))) == 1){$isRoot = true;}
if(!$source['shareID']){$isRoot = true;}
$source['sourceInfo']['shareIsRoot'] = $isRoot;
if(!$isRoot) return; // 子文件夹不显示协作成员;
$source['shareTarget'] = $this->shareTargetMake($share['authList']);
}
public function shareTargetMake($authList){
$userArr = array();$groupArr = array();
foreach($authList as $item){
$auth = Model("SourceAuth")->authInfo($item);
if($item['targetType'] == SourceModel::TYPE_GROUP){
$item = Model("Group")->getInfoSimple($item['targetID']);
$item['auth'] = $auth;$groupArr[] = $item;
}else{
$item = Model("User")->getInfoSimpleOuter($item['targetID']);
$item['auth'] = $auth;$userArr[] = $item;
}
}
return array_merge($groupArr,$userArr);
}
/**
* 添加分享;
*/
public function add(){
$data = $this->_getParam('sourceID');
$pathParse = KodIO::parse($data['path']);
$this->checkRoleAuth($data['isLink'] ? 'shareLink':'shareTo');
// 物理路径,io路径;
$data['sourcePath'] = KodIO::clear($data['path']);
if( $pathParse['type'] == KodIO::KOD_IO || !$pathParse['type'] ){
$result = $this->model->shareAdd('0',$data);
}else{
$sourceID = KodIO::sourceID($data['path']);
$pathInfo = Model('Source')->pathInfo($sourceID);
$this->checkSetAuthAllow($data['authTo'],$pathInfo);
$result = $this->model->shareAdd($sourceID,$data);
}
if(!$result) show_json(LNG('explorer.error'),false);
$shareInfo = $this->model->getInfo($result);
$shareInfo = Action('explorer.shareOut')->sendShareSiteAppend($shareInfo);
show_json($shareInfo,true);
}
/**
* 编辑分享
*/
public function edit(){
$data = $this->_getParam('shareID');
$this->checkRoleAuth($data['isLink'] == '1' ? 'shareLink':'shareTo');
$shareInfo = $this->getShareInfo($data['shareID']);
$this->checkSetAuthAllow($data['authTo'],$shareInfo['sourceInfo']);
$result = $this->model->shareEdit($data['shareID'],$data);
// 编辑后不检测权限(与我协作-管理者,移除或降低自己的权限)
if(!$result){show_json("[URL] ".LNG('explorer.pathExists'),false);}
show_json($this->getShareInfo($data['shareID'],false));
}
// 协作分享: 可以设置的权限,必须小于等于自己在当前文档的权限;
public function checkSetAuthAllow($authTo,$pathInfo){
if(!$authTo || !$pathInfo || !$pathInfo['auth']) return;
$selfAuth = intval($pathInfo['auth']['authInfo']['auth']);
foreach ($authTo as $authItem){
$authInfo = Model("Auth")->listData($authItem['authID']);
$authBoth = $selfAuth | intval($authInfo['auth']);
if($authBoth == $selfAuth) continue;
show_json(LNG('admin.auth.errorAdmin'),false);
}
}
private function checkRoleAuth($shareType){
if(KodUser::isRoot()){return;}
$canShareTo = Action('user.authRole')->authCan('explorer.share');
$canShareLink = Action('user.authRole')->authCan('explorer.shareLink');
if($shareType == 'shareTo' && !$canShareTo){
show_json(LNG('explorer.noPermissionAction'),false,1004);
}
if($shareType == 'shareLink' && !$canShareLink){
show_json(LNG('explorer.noPermissionAction'),false,1004);
}
}
/**
* 添加/编辑分享;
* shareType:
* 0: 暂未指定分享
* 1: 内部指定用户分享
* 2: 外链分享
* 3: 内部指定、外链分享同时包含
*
* 外链分享; title,password,timeTo,options
* authTo: [
* {"targetType":"1","targetID":"23","authID":"1"},
* {"targetType":"2","targetID":"3","authDefine":"512"}
* ]
* param: title,password,timeTo,options
*/
private function _getParam($key='shareID'){
$keys = array(
"isLink" => array("check"=>"bool", "default"=>0),
"isShareTo" => array("check"=>"bool", "default"=>0),
"title" => array("check"=>"require","default"=>''),
"password" => array("default"=>''),//密码设置为空处理;
"timeTo" => array("check"=>"require","default"=>0),
"options" => array("check"=>"json", "default"=>array()),
"authTo" => array("check"=>"json", "default"=>array()),
);
//修改,默认值为null不修改;
if($key == 'shareID'){
$keys['shareID'] = array("check"=>"int");
foreach ($keys as $key => &$value) {
$value['default'] = null;
};unset($value);
}else{//添加时,目录值
$keys['path'] = array("check"=>"require");
}
$data = Input::getArray($keys);
// 外链分享检测;
if($data['isLink'] == '1'){
$options = Model('SystemOption')->get();
if($options['shareLinkAllow'] == '0'){
show_json(LNG('admin.setting.shareLinkAllowTips'),false);
}
if($options['shareLinkPasswordAllowEmpty'] == '0' && !$data['password']){
show_json(LNG('user.pwdNotNull'),false);
}
if($options['shareLinkAllowGuest'] == '0'){
$data["options"]['onlyLogin'] = '1';
}
// 外链分享,分享者角色没有上传权限时, 不允许开启允许上传;
if(!Action('user.authRole')->authCan('explorer.upload')){
$data["options"]['canUpload'] = '0';
$data["options"]['canEditSave'] = '0';
if($options['shareLinkAllowEdit'] == '0'){$data["options"]['canEditSave'] = '0';}
}
if(_get($this->in,'hash')){
$data['shareHash'] = trim(rawurldecode($this->in['hash']));
$data['shareHash'] = substr(preg_replace('/[^\w\-\._]/', '_', $data['shareHash']),0,45);
}
}
return $data;
}
/**
* 批量取消分享;
* 如果制定了分享类型: 则不直接删除数据;
*/
public function del() {
$list = Input::get('dataArr','json');
$shareType = _get($this->in,'type','');
// 批量删除指定内部协作分享, or外链分享;
foreach ($list as $shareID) {
$shareInfo = $this->model->getInfo($shareID);
if(!$shareInfo || $shareInfo['userID'] != KodUser::id()){continue;}
if(!$shareType){
$res = $this->model->remove(array($shareID));
continue;
}
$res = $this->removeShare($shareInfo,$shareType);
}
$msg = !!$res ? LNG('explorer.success'): LNG('explorer.error');
show_json($msg,!!$res);
}
public function removeShare($shareInfo,$shareType){
$this->checkRoleAuth($shareType == 'shareTo' ? 'shareTo':'shareLink');
if($shareType == 'shareTo'){
$data = array('isShareTo'=>0,'authTo'=>array(),'options'=>$shareInfo['options']);
if(isset($data['options']['shareToTimeout'])){unset($data['options']['shareToTimeout']);}
}else{
$data = array('isLink'=>0,'options'=>$shareInfo['options']);
if(is_array($data['options'])){
unset($data['options']['onlyLogin']);
unset($data['options']['pageType']);
unset($data['options']['shareOut']);
}
}
// 都为空时则删除数据, 再次分享shareID更新;
if( $data['isLink'] == 0 && $shareInfo['isShareTo'] == 0 ||
$data['isShareTo'] == 0 && $shareInfo['isLink'] == 0 ){
return $this->model->remove(array($shareInfo['shareID']));
}
return $this->model->shareEdit($shareInfo['shareID'],$data);
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/userShareGroup.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
按组织架构对与我协助内容进行归类
1. 子部门: 该部门子部门,下级部门有分享或下级成员有分享时显示
2. 部门成员的个人空间分享; 包含个人空间文件,其他物理路径,外部部门空间分享;
3. 该部门空间协作分享: 该部门空间内容;
----
4. 外部协作分享: 不在自己组织架构下的外部用户的协作分享;
*/
class explorerUserShareGroup extends Controller{
private $model;
private $userGroupRootShow;
private $shareListData;
function __construct(){
parent::__construct();
$this->model = Model('Share');
}
public function get($id){
$this->userGroupRootShow = Action('filter.userGroup')->userGroupRootShow();
$this->shareListData = $this->shareListDataMake();
if(!$id || $id == 'group'){
return $this->listRoot();
}
$userPre = 'group-u';//group-u101-23; userID-parentGroup
$groupPre = 'group-g';//group-g101;
if(substr($id,0,strlen($groupPre)) == $groupPre){
$groupID = substr($id,strlen($groupPre));
return $this->listByGroup($groupID);
}
if(substr($id,0,strlen($userPre)) == $userPre){
$userGroup = explode('-',substr($id,strlen($userPre)));
return $this->listByUser($userGroup[0],$userGroup[1]);
}
}
private function listRoot(){
$rootCount = count($this->userGroupRootShow);
if($rootCount == 0) return false;
$outUserList = $this->listUserOuter();
if($rootCount == 1){
return $this->listRootSingle($this->userGroupRootShow[0],$outUserList);
}
$childrenGroup = Model("Group")->listByID($this->userGroupRootShow);
$childrenGroup = array_sort_by($childrenGroup,'sort',false);
$groupList = array();
foreach($childrenGroup as $groupInfo){
$childList = $this->listByGroup($groupInfo['groupID']);
if(!$childList || (!$childList['groupList'] && !$childList['folderList'])){continue;}
$groupList[] = $this->makeItemGroup($groupInfo);
}
if(!$groupList) return false;
if(count($groupList) == 1){
return $this->listRootSingle($groupList[0]['groupID'],$outUserList);
}
$result = $this->listByGroupType(array('groupList'=>$groupList));
$result['groupList'] = array_merge($result['groupList'],$outUserList);
return $result;
}
private function listRootSingle($groupID,$outUserList){
$result = $this->listByGroup($groupID);
$desc = '['.LNG('admin.setting.shareToMeGroup').'],'.LNG('explorer.pathDesc.shareToMeGroup');
if($result){$result['currentFieldAdd'] = array("pathDesc"=>$desc);}
// 合并外部分享信息数据;
if(!$result['groupList']){$result['groupList'] = array();}
$result['groupList'] = array_merge($result['groupList'],$outUserList);
return $result;
}
// 当前部门有分享内容的子部门, 当前部门分享内容, 当前部门有分享内容的用户;
private function listByGroup($groupID){
$groupID = intval($groupID);
if(!$groupID) return false;
$groupInfoCurrent = Model("Group")->getInfo($groupID);
if(!$groupInfoCurrent) return false;
$listData = $this->shareListData;
$groupArray = array_keys($listData['group']);
$userArray = array_keys($listData['user']);
$goupList = Model("Group")->listByID($groupArray);
$userList = Model("User")->listByID($userArray);
$childrenUser = array();
$childrenGroup = array();
foreach($goupList as $groupInfo){
$groupLevel = $groupInfo['parentLevel'].$groupInfo['groupID'].',';//层级
$childrenID = $this->groupChildrenMake($groupID,$groupLevel);
if($childrenID){$childrenGroup[] = $childrenID;}
}
foreach ($userList as $userInfo){
foreach ($userInfo['groupInfo'] as $groupInfo){
$groupLevel = $groupInfo['parentLevel'].$groupInfo['groupID'].',';//层级
$childrenID = $this->groupChildrenMake($groupID,$groupLevel);
if($childrenID){$childrenGroup[] = $childrenID;}
if($groupInfo['groupID'] == $groupID){$childrenUser[] = $userInfo;}
}
}
$childrenGroup = Model("Group")->listByID(array_unique($childrenGroup));
$childrenGroup = array_sort_by($childrenGroup,'sort',false);
$groupList = array();
foreach($childrenGroup as $groupInfo){$groupList[] = $this->makeItemGroup($groupInfo);}
foreach($childrenUser as $userInfo){$groupList[] = $this->makeItemUser($userInfo,$groupInfoCurrent);}
$result = array('groupList'=>$groupList,'folderList'=>$listData['group'][$groupID]);
$result['currentFieldAdd'] = $this->makeItemGroup($groupInfoCurrent);
$result = $this->listByGroupType($result);
return $result;
}
private function listByGroupType($result){
if(!$result['folderList']){$result['folderList'] = array();}
if(!$result['fileList']){$result['fileList'] = array();}
$result['groupShow'] = array(
array(
'type' => 'childGroup',
'title' => LNG("explorer.pathGroup.shareGroup"),
'desc' => LNG("explorer.pathGroup.shareGroupDesc"),
"filter"=> array('groupID'=>'')
),
array(
'type' => 'childUser',
'title' => LNG("explorer.pathGroup.shareUser"),
'desc' => LNG("explorer.pathGroup.shareUserDesc"),
"filter"=> array('userID'=>'','shareFrom'=>'!=outer')
),
array(
'type' => 'childUserOuter',
'title' => LNG('explorer.pathGroup.shareUserOuter'),
"desc" => LNG("explorer.pathGroup.shareUserOuterDesc"),
"filter"=> array('shareFrom'=>'outer')
),
array(
'type' => 'childContent',
'title' => LNG("explorer.pathGroup.shareContent"),
"filter"=> array('shareID'=>'')
),
);
if(count($result['groupList']) == 0){unset($result['groupShow']);}
// filter 支持多个key-value; 全匹配才算匹配;
// value为*则检测是否有该key; 为字符串则检测相等; value为数组则代表可选值集合
// show_json([$groupID,$groupList,$result]);exit;
return $result;
}
// $groupID是否为$parentLevel的上层部门; 如果是则返回$groupID下一层部门id;
private function groupChildrenMake($groupID,$checkLevel){
$level = explode(',',trim($checkLevel,','));
$level = array_remove_value($level,'0');
$index = array_search($groupID,$level);
if($index === false || $index == count($level) - 1) return false;
return $level[$index + 1];
}
public function groupAllowShow($groupID,$parentLevel=false){
$allow = false;
if(in_array($groupID,$this->userGroupRootShow)) return true;
if(!$parentLevel){
$groupInfo = Model('Group')->getInfo($groupID);
$parentLevel = $groupInfo['parentLevel'].$groupInfo['groupID'].',';
}
foreach($this->userGroupRootShow as $group){
if($this->groupChildrenMake($group,$parentLevel)){$allow = true;break;}
}
return $allow;
}
private function makeItemGroup($groupInfo){
$result = array(
"groupID" => $groupInfo['groupID'],
"name" => $groupInfo["name"],
"type" => "folder",
"path" => "{shareToMe:group-g".$groupInfo['groupID']."}/",
"icon" => "root-groupPath",
"pathDesc" => LNG('explorer.pathDesc.shareToMeGroupGroup'),
);
$parentGroup = Model("Group")->getInfo($groupInfo['parentID']);
return $this->makeAddress($result,$parentGroup);
}
private function makeItemUser($userInfo,$parentGroup=false){
$defaultThumb = STATIC_PATH.'images/common/default-avata.png';
$defaultThumb = 'root-user-avatar';// $userInfo["avatar"] = false;
$parentGroup = $parentGroup ? $parentGroup:array('groupID'=>'0','parentLevel'=>'');
$result = array(
"userID" => $userInfo['userID'],
"name" => $userInfo['nickName'] ? $userInfo['nickName']:$userInfo['name'],
"type" => "folder",
"path" => "{shareToMe:group-u".$userInfo['userID']."-".$parentGroup['groupID']."}/",
"icon" => $userInfo["avatar"] ? $userInfo["avatar"]:$defaultThumb,//fileThumb,icon
"iconClassName" => 'user-avatar',
);
$result['pathDescAdd'][] = array(
"title" => LNG("common.desc"),
"content" => LNG('explorer.pathGroup.shareUserDesc')
);
$userInfo = Model('User')->getInfo($userInfo['userID']);
$groupArr = array_to_keyvalue($userInfo['groupInfo'],'','groupName');
if($groupArr){
$result['pathDescAdd'][] = array("title"=>LNG("admin.member.group"),"content"=>implode(',',$groupArr));
}
return $this->makeAddress($result,$parentGroup);
}
private function makeAddress($itemInfo,$parentGroup){
$address = array(array("name"=> LNG('explorer.toolbar.shareToMe'),"path"=>'{shareToMe}'));
// 从$this->uuserGroupRootShow的某一个,开始到$groupInfo所在部门
$level = $parentGroup ? $parentGroup['parentLevel'].$parentGroup['groupID'].',':'';
$level = explode(',',trim($level,','));
$level = array_remove_value($level,'0');
$fromAdd = count($this->userGroupRootShow) == 1 ? 1: 0;//只有一个根部门,则忽略根部门;
$index = false;
if($level){
foreach($this->userGroupRootShow as $groupID){
$index = array_search($groupID,$level);
if($index !== false){break;}
}
}
if($index !== false){
$nameArray = explode('/',trim($parentGroup['groupPath']));
for ($i=$index+$fromAdd; $i < count($level); $i++) {
$address[] = array("name"=> $nameArray[$i],"path"=>"{shareToMe:group-g".$level[$i]."}/");
}
}
$address[] = array("name"=> $itemInfo["name"],"path"=>$itemInfo['path']);
$itemInfo['pathAddress'] = $address;
return $itemInfo;
}
private function listByUser($userID,$parentGroup){
$userShareList = $this->shareListData['user'][$userID];
if(!$userShareList) return false;
$userInfo = Model('User')->getInfoSimpleOuter($userID);
$result = Action('explorer.userShare')->shareToMeListMake($userShareList);
$groupInfo = Model('Group')->getInfo($parentGroup);
$result['currentFieldAdd'] = $this->makeItemUser($userInfo,$groupInfo);
// unset($result['currentFieldAdd']['icon']);
return $result;
}
// 对内容归类整理: 所属用户,所属部门,
private function shareListDataMake(){
$shareList = $this->model->listToMe(5000);
$sourceArray = array_to_keyvalue($shareList['list'],'','sourceID');
$sourceArray = array_unique($sourceArray);
if($sourceArray){
$where = array('sourceID' => array('in',$sourceArray),'isDelete' => 0,);
$sourceList = Model('Source')->listSource($where);
$sourceArray = array_merge($sourceList['folderList'],$sourceList['fileList']);
$sourceArray = array_to_keyvalue($sourceArray,'sourceID');
}
$userList = array();$groupList = array();
foreach ($shareList['list'] as $shareItem){
$timeout = intval(_get($shareItem,'options.shareToTimeout',0));
if($timeout > 0 && $timeout < time()) continue;// 过期内容;
if($shareItem['sourceID'] == '0'){// 物理路径,io路径;
// $info = IO::info($shareItem['sourcePath']);
$info = $shareItem;//性能优化, 拉取用户内容时才考虑;
}else{
$info = $sourceArray[$shareItem['sourceID']];
}
if(!$info) continue;
$groupNotAllowShare = false;// 部门内容分享,该部门对自己不可见则归类到该用户的分享;
if($info['targetType'] == 'group' && !$this->groupAllowShow($info['targetID'])){
$groupNotAllowShare = true;
}
if($groupNotAllowShare || $shareItem['sourceID'] == '0' || $info['targetType'] == 'user'){// 物理路径,io路径;
$userID = $shareItem['userID'];
if(!isset($userList[$userID])){$userList[$userID] = array();}
$userList[$userID][] = $shareItem;//性能优化;
}else{
$info = Action('explorer.userShare')->_shareItemeParse($info,$shareItem);
if(!$info) continue;
$groupID = $info['targetID'];
if(!isset($groupList[$groupID])){$groupList[$groupID] = array();}
$groupList[$groupID][] = $info;
}
}
return array('user'=>$userList,'group'=>$groupList);
}
// 筛选出外部分享内容; 部门空间内容-部门不在该自己所在组织架构内; 个人空间分享--个人不在自己所在组织架构内;
// 按人进行归类;
private function listUserOuter(){
$userList = array();
foreach($this->shareListData['user'] as $userID=>$userShare){
$userInfo = Model('User')->getInfo($userID);
$userAllow = false;
if(!$userInfo){$userInfo = Model('User')->getInfoSimpleOuter($userID);}
foreach ($userInfo['groupInfo'] as $groupInfo){
$groupLevel = $groupInfo['parentLevel'].$groupInfo['groupID'].',';//层级
if($this->groupAllowShow($groupInfo['groupID'],$groupLevel)){$userAllow = true;break;}
}
if($userAllow) continue;
$userItem = $this->makeItemUser($userInfo);
$userItem['shareFrom'] = 'outer';
$userList[] = $userItem;
}
return $userList;
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/userShareTarget.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
/**
* 最近分享目标获取;
*
* 最近分享/权限设置出的用户及部门,按次数排序,总共10个,部门在前用户在后;
* 数据缓存; 新查询数据合并之前缓存数据;(避免取消分享后没有最近使用的情况)
*/
class explorerUserShareTarget extends Controller{
function __construct(){
parent::__construct();
}
public function save(){
$data = Input::getArray(array(
"name" => array("check"=>"require"),
"authTo" => array("check"=>"require","default"=>''),
));
//编辑保存
$saveData = $this->dataValue('saveData');
if($this->in['beforeName']){
unset($saveData[$this->in['beforeName']]);
}
$data['modifyTime'] = time();
$saveData[$data['name']] = $data;
// authTo为空则代表删除
if(!$data['authTo']){
unset($saveData[$data['name']]);
}
$this->dataValue('saveData',$saveData);
$result = $this->get(10);
show_json($result,true);
}
public function get($maxNumber){
$maxNumber = 10; // 最多条数
$list = $this->targetMake();
foreach ($list as $targetType => $targetList){
$list[$targetType] = array();
foreach ($targetList as $info){
if($targetType == 'group'){
$targetInfo = Model("Group")->getInfo($info['id']);
}else{
$targetInfo = Model("User")->getInfoSimpleOuter($info['id']);
if($targetInfo['userID'] == '0' || $targetInfo['userID'] == '-1'){
$targetInfo = false;
}
}
if(!$targetInfo) continue;
$list[$targetType][] = $targetInfo;
}
}
if( count($list['user']) + count($list['group']) > $maxNumber ){
$list['user'] = array_slice($list['user'], 0,$maxNumber / 2);
$list['group'] = array_slice($list['group'],0,$maxNumber / 2);
}
$saveData = $this->dataValue('saveData');
foreach ($saveData as $key=>$value){
$value['nodeAddClass'] = 'node-share-item-store';
$value['icon'] = '<i class="font-icon ri-team-fill"></i>';
$saveData[$key] = $value;
}
$saveData = array_values($saveData);
$result = array_merge($saveData,$list['group'],$list['user']);
return $result;
}
private function dataValue($key,$value=false){
if($value === false){
// Model("UserOption")->set($key,null,'shareTarget');
$theValue = Model("UserOption")->get($key,'shareTarget',1);
$theValue = is_array($theValue) ? $theValue : array();
}else{
Model("UserOption")->set($key,$value,'shareTarget');
}
return $theValue;
}
/**
* 新查询的数据合并之前数据;
*
* 实时中id存在旧数据中不存在, 则设置id的count为实时数据的count
* 实时中id存在旧数据中已经存在, 则使用count更大的作为当前id的count;
* 旧数据中有,实时中id不存在, 检测对象是否存在,存在则id的count重置为1,不存在则从缓存中移除;
*/
private function targetMake(){
$listNow = $this->targetSelect();$listNowData = $listNow;
$listBefore = $this->dataValue('cacheData');
foreach ($listNow as $targetType => $targetList){
foreach ($targetList as $id=>$info){
$beforeItem = $listBefore[$targetType][$id];
if($beforeItem){
$info['count'] = max($info['count'],$beforeItem['count']);
$listNow[$targetType][$id] = $info;
}
}
}
// 缓存中有,新查询不存在
foreach ($listBefore as $targetType => $targetList){
foreach ($targetList as $id=>$info){
if(!$listNow[$targetType][$id]){
if($targetType == 'group'){
$targetInfo = Model("Group")->getInfo($info['id']);
}else{
$targetInfo = Model("User")->getInfoSimpleOuter($info['id']);
}
if(!$targetInfo) continue;
$info['count'] = 1;
$listNow[$targetType][$id] = $info;
}
}
$listNow[$targetType] = array_sort_by($listNow[$targetType] ,'count',true);
$listNow[$targetType] = array_to_keyvalue($listNow[$targetType] ,'id');
}
if($listNow != $listBefore){
$this->dataValue('cacheData',$listNow);
}
// pr($listNow == $listBefore,$listNowData,$listBefore,$listNow);exit;
return $listNow;
}
private function targetSelect(){
$shareList = Model('Share')->listSimple();
$shareList = array_filter_by_field($shareList,'isShareTo','1');
$shareIdList = array_to_keyvalue($shareList,'','shareID');
if(!$shareIdList) return array('group'=>array(),'user'=>array());
$where = array('shareID' => array('in',$shareIdList));
$toList = Model("share_to")->where($where)->select();
return array(
'group' => $this->targetSort($toList,SourceModel::TYPE_GROUP),
'user' => $this->targetSort($toList,SourceModel::TYPE_USER)
);
}
private function targetSort($shareList,$type){
$list = array_filter_by_field($shareList,'targetType',$type.'');
$list = array_to_keyvalue_group($list,'targetID','targetID');
foreach ($list as $key => $value) {
$list[$key] = array('id'=>$key,'count'=>count($value));
}
$list = array_sort_by($list,'count',true);
return array_to_keyvalue($list,'id');
}
}
wget 'https://sme10.lists2.roe3.org/kodbox/app/controller/explorer/userShareUser.class.php'
<?php
/*
* @link http://kodcloud.com/
* @author warlee | e-mail:kodcloud@qq.com
* @copyright warlee 2014.(Shanghai)Co.,Ltd
* @license http://kodcloud.com/tools/license/license.txt
*/
class explorerUserShareUser extends Controller{
private $model;
function __construct(){
parent::__construct();
$this->model = Model('Share');
}
public function get($id){
if(!$id || $id == 'user') return $this->listRoot();
return $this->listByUser(substr($id,strlen('user-')));
}
private function listRoot(){
$shareList = $this->model->listToMe(5000);
$userArray = array_to_keyvalue($shareList['list'],'','userID');
$userArray = array_unique($userArray);
$folderList= array();
foreach($userArray as $userID ){
$folderList[] = $this->makeItemUser(Model('User')->getInfoSimpleOuter($userID));
}
$result = array('fileList'=>array(),'folderList'=>$folderList);//,"disableSort"=>true
$result['currentFieldAdd'] = array("pathDesc"=>'['.LNG('admin.setting.shareToMeUser').'],'.LNG('explorer.pathDesc.shareToMeUser'));
return $result;
}
private function listByUser($userID){
$shareList = $this->model->listToMe(5000);
$listData = array();
foreach ($shareList['list'] as $shareItem){
if($shareItem['userID'] == $userID){$listData[] = $shareItem;}
}
$result = Action('explorer.userShare')->shareToMeListMake($listData);
$result['currentFieldAdd'] = $this->makeItemUser(Model('User')->getInfoSimpleOuter($userID));
return $result;
}
private function makeItemUser($userInfo){
$defaultThumb = STATIC_PATH.'images/common/default-avata.png';
$defaultThumb = 'root-user-avatar';// $userInfo["avatar"] = false;
$result = array(
"name" => $userInfo['nickName'] ? $userInfo['nickName']:$userInfo['name'],
"type" => "folder",
"path" => "{shareToMe:user-".$userInfo['userID']."}/",
"icon" => $userInfo["avatar"] ? $userInfo["avatar"]:$defaultThumb,//fileThumb,icon
"iconClassName" => 'user-avatar',
);
$result['pathDescAdd'][] = array(
"title" => LNG("common.desc"),
"content" => LNG('explorer.pathDesc.shareToMeUserItem')
);
$userInfo = Model('User')->getInfo($userInfo['userID']);
$groupArr = array_to_keyvalue($userInfo['groupInfo'],'','groupName');
if($groupArr){
$result['pathDescAdd'][] = array("title"=>LNG("admin.member.group"),"content"=>implode(',',$groupArr));
}
return $this->makeAddress($result);
}
private function makeAddress($itemInfo){
$address = array(array("name"=> LNG('explorer.toolbar.shareToMe'),"path"=>'{shareToMe}'));
$address[] = array("name"=> $itemInfo["name"],"path"=>$itemInfo['path']);
$itemInfo['pathAddress'] = $address;
return $itemInfo;
}
}