Repository: Mintimate/OneindexM Branch: master Commit: ee9c63a9681d Files: 87 Total size: 471.0 KB Directory structure: gitextract_zkw3fajl/ ├── .gitignore ├── README.md ├── cache/ │ └── abc ├── config/ │ └── README.md ├── controller/ │ ├── AdminController.php │ ├── CommonController.php │ ├── ImagesController.php │ ├── IndexController.php │ └── UploadController.php ├── index.php ├── init.php ├── lib/ │ ├── Parsedown.php │ ├── cache/ │ │ ├── filecache_.php │ │ ├── memcache_.php │ │ ├── redis_.php │ │ └── secache_.php │ ├── cache.php │ ├── fetch.php │ ├── onedrive.php │ ├── oneindex.php │ ├── route.php │ ├── sqlite.php │ └── view.php ├── one.php ├── statics/ │ ├── common/ │ │ ├── offline/ │ │ │ ├── css/ │ │ │ │ └── main.css │ │ │ └── js/ │ │ │ ├── aria2.js │ │ │ ├── jquery.Storage.js │ │ │ ├── jquery.jsonrpc.js │ │ │ ├── mustache.js │ │ │ ├── peerid.js │ │ │ └── yaaw-1.1.js │ │ └── search/ │ │ └── js/ │ │ └── search.js │ └── themes/ │ └── nexmoe/ │ ├── css/ │ │ └── forkGh.css │ └── js/ │ ├── nexmoe.js │ └── personjs.js ├── view/ │ ├── admin/ │ │ ├── cache.php │ │ ├── images.php │ │ ├── install/ │ │ │ ├── install_0.php │ │ │ ├── install_1.php │ │ │ ├── install_2.php │ │ │ ├── install_3.php │ │ │ └── layout.php │ │ ├── layout.php │ │ ├── login.php │ │ ├── offline.php │ │ ├── setpass.php │ │ ├── settings.php │ │ ├── show.php │ │ └── upload.php │ ├── common/ │ │ ├── offline.php │ │ ├── search.php │ │ └── tips.php │ └── themes/ │ ├── classic/ │ │ ├── 404.php │ │ ├── layout.php │ │ └── list.php │ ├── material/ │ │ ├── 404.php │ │ ├── images/ │ │ │ ├── index.php │ │ │ └── layout.php │ │ ├── layout.php │ │ ├── list.php │ │ ├── password.php │ │ └── show/ │ │ ├── audio.php │ │ ├── code.php │ │ ├── doc.php │ │ ├── image.php │ │ ├── pdf.php │ │ ├── stream.php │ │ ├── video.php │ │ ├── video2.php │ │ └── video5.php │ └── nexmoe/ │ ├── 404.php │ ├── images/ │ │ ├── index.php │ │ └── layout.php │ ├── layout.php │ ├── list.php │ ├── password.php │ ├── readme.html │ └── show/ │ ├── audio.php │ ├── code.php │ ├── doc.php │ ├── image.php │ ├── pdf.php │ ├── stream.php │ ├── video.php │ ├── video2.php │ └── video5.php └── 使用及免责协议.md ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ **/.DS_Store ================================================ FILE: README.md ================================================ ## 简介 本项目是基于: - Oneindex - OneindexN项目地址:https://github.com/xieqifei/OneindexN 详细安装教程: - [基于Onedrive和Server搭建下载站/网盘](https://www.mintimate.cn/2020/09/22/oneindex) 教程视频: - [8分钟利用OneDrive搭建不限速的OneIndex分享网盘](https://www.bilibili.com/video/BV1ph41197aa) 打赏 - 爱发电:[Mintimate的电圈](https://www.afdian.net/@mintimate/plan) ![](https://cdn.jsdelivr.net/gh/Mintimate/OneindexM/demo/demo.png) ### 特别注意 OneindexM的默认密码为:**MintimateBlog** ## 修改功能: ### 后台: - 选择安装世纪互联/国际版(如需修改版本,需要删除config文件夹里的文件后重新进入安装程序) - 指定文件夹/全部文件夹,关闭Readme.md、index.html、head.md渲染(如果开启游客离线上传,可以关闭此路径的渲染,避免游客上传会被渲染的文件。) ### 前台 以下功能仅支持nexmoe主题 - 搜索功能:全局搜索/当前页过滤 - 文件操作:删除/新建/重命名/剪切/复制/分享等。仅管理员可用 - 文件上传:4M以下的文件在线上传。url远程上传,仅onedrive个人版支持。aria2离线上传,需自行安装在vps上安装aria2并完成相关配置。 - 外部视频播放器播放接口。需要安装对应播放器。 - 管理员登陆后,查看加密文件夹无需密码。 ## 更新日志 - 2021.12.03:修复PHP7.x查询函数警告问题;修复文件过滤、查询出错问题;修复排序不可用问题;移除Jq、Bootstrap;调整部分UI - 2021.08.03:修复Cookies循环问题、修复世纪互联版本部分情况不可用问题。 - 2021.07.01:修复因为Onedrive接口更换,而导致的无法部署。 - 2021.06.25:更换重写URL服务器。 ## 部署网站 网站环境尽量使用Nginx或Apache,配合PHP5.7+版本。 建议参考文章: ![基于Onedrive和Server搭建下载站/网盘](https://www.mintimate.cn/2020/09/22/oneindex)
**以下是上游Readme.md内容** ## 功能 不占用服务器空间,不走服务器流量, 直接列出 OneDrive 目录,文件直链下载。 ## 使用及免责协议 [使用及免责协议](./使用及免责协议.md) ## 安装运行 ### 需求: 1、PHP空间,PHP 5.6+ 需打开curl支持 2、OneDrive 账号 (个人、企业版或教育版/工作或学校帐户) 3、OneIndex 程序 ### 计划任务   [可选]**推荐配置**,非必需。后台定时刷新缓存,可增加前台访问的速度。 ``` # 每小时刷新一次token 0 * * * * /具体路径/php /程序具体路径/one.php token:refresh # 每十分钟后台刷新一遍缓存 */10 * * * * /具体路径/php /程序具体路径/one.php cache:refresh ``` ### Docker 安装运行 - 请参考[TimeBye/oneindex](https://github.com/TimeBye/oneindex) ## 特殊文件实现功能   ` README.md `、`HEAD.md` 、 `.password`特殊文件使用 可以参考[https://github.com/donwa/oneindex/tree/files](https://github.com/donwa/oneindex/tree/files) **在文件夹底部添加说明:**   >在 OneDrive 的文件夹中添加` README.md `文件,使用 Markdown 语法。 **在文件夹头部添加说明:**   >在 OneDrive 的文件夹中添加`HEAD.md` 文件,使用 Markdown 语法。 **加密文件夹:**   >在 OneDrive 的文件夹中添加`.password`文件,填入密码,密码不能为空。   **直接输出网页:** >在 OneDrive 的文件夹中添加`index.html` 文件,程序会直接输出网页而不列目录。 >配合 文件展示设置-直接输出 效果更佳。 ## 命令行功能   仅能在PHP CLI模式下运行 **清除缓存:**   ``` php one.php cache:clear ``` **刷新缓存:**   ``` php one.php cache:refresh ``` **刷新令牌:**   ``` php one.php token:refresh ``` **上传文件:**   ``` php one.php upload:file 本地文件 [OneDrive文件] ``` **上传文件夹:** ``` php one.php upload:folder 本地文件夹 [OneDrive文件夹] ``` 例如: ``` //上传demo.zip 到OneDrive 根目录 php one.php upload:file demo.zip //上传demo.zip 到OneDrive /test/目录 php one.php upload:file demo.zip /test/ //上传demo.zip 到OneDrive /test/目录并将其命名为 d.zip php one.php upload:file demo.zip /test/d.zip //上传up/ 到OneDrive /test/ 目录 php one.php upload:file up/ /test/ ``` ## 使用Aria2 Nginx添加反向代理 ``` location /jsonrpc { proxy_pass http://localhost:6800/jsonrpc; proxy_redirect off; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; } ``` nginx会监听发送给`http://yoursite/jsonrpc`的消息,然后将他转发给`http:localhost:6800/jsonrpc`,相当于你在yaaw中设置rpc时,只需要将其设置为`http://yoursite/jsonrpc`或者`https://yoursite/jsonrpc`,省略的端口信息为http对应80,https对应443,这些端口浏览器会自动转发,不用在设置中指定。如果你设置了反向代理,那么使用前台yaaw时,就不用在做rpc设置了。否则你需要去重新设置。 ![](https://i.loli.net/2020/06/25/9cY2PiBr6usqXen.png) **关闭aria2远程RPC** 仅vps本地也就是nginx转发的请求能到达6800。其他主机不能访问6800端口。 ```shell vim /root/.aria2c/aria2.conf ``` 修改aria2配置内容 ``` # 启用RPC, 默认:false enable-rpc=true # 接受所有远程请求, 默认:false rpc-allow-origin-all=false # 允许外部访问, 默认:false rpc-listen-all=false # RPC监听端口, 端口被占用时可以修改, 默认:6800 rpc-listen-port=6800 ``` > 请注意,关闭远程请求并不能阻止其他主机向aria2发送请求,在不设置token时,任何人都可以通过直接向`http://yoursite/jsonrpc`这个地址发送请求连接aria2。如果你开启游客离线下载可以这么设置。如果你不希望有人通过其他aria2前端连接你的aria2,请你务必设置token,但是这样做,你也必须在使用的时候修改rpc设置,好在,第一次修改设置后,之后浏览器都会记住这个设置。 > 博客:https://sci.ci > > 如果应用有bug,或者你有好的修改建议,可以通过邮箱联系我:im@xieqifei.com ## 参考资料 《[github YAAW项目](https://github.com/binux/yaaw)》 《[Issue:一旦使用HTTPS协议就无法连接](https://github.com/mayswind/AriaNg/issues/62)》 《[Nginx 反向代理 Aria2 JSONRPC](https://kenvix.com/post/nginx-proxy-aria2/)》 ================================================ FILE: cache/abc ================================================ ================================================ FILE: config/README.md ================================================ # oneindex OneDrive Directory Index ================================================ FILE: controller/AdminController.php ================================================ 'OneIndex', 'site_name_small' =>'', 'password' => 'MintimateBlog', 'style'=>'nexmoe', 'onedrive_root' =>'', 'except_path' =>'', 'cache_type'=>'secache', 'cache_expire_time' => 10, 'cache_refresh_time' => 600, 'root_path' => '?', 'show'=> array ( 'stream'=>['txt'], 'image' => ['bmp','jpg','jpeg','png','gif'], 'video5'=>['mp4','webm','mkv'], 'video'=>[], 'video2'=>['avi','mpg', 'mpeg', 'rm', 'rmvb', 'mov', 'wmv', 'asf', 'ts', 'flv'], 'audio'=>['ogg','mp3','wav'], 'code'=>['html','htm','php', 'css', 'go','java','js','json','txt','sh','md'], 'doc'=>['csv','doc','docx','odp','ods','odt','pot','potm','potx','pps','ppsx','ppsxm','ppt','pptm','pptx','rtf','xls','xlsx'] ), 'images'=>['home'=>false,'public'=>false, 'exts'=>['jpg','png','gif','bmp']], 'offline'=>array( 'offline'=>false, 'online'=>false, 'upload_path'=>'/upload/' ) ); function __construct(){ } function login(){ if(!empty($_POST['password']) && $_POST['password'] == config('password')){ setcookie('admin', md5(config('password').config('refresh_token')) ); return view::direct(get_absolute_path(dirname($_SERVER['SCRIPT_NAME'])).'?/admin/'); } return view::load('login')->with('title', '系统管理'); } function logout(){ setcookie('admin', '' ); return view::direct(get_absolute_path(dirname($_SERVER['SCRIPT_NAME'])).'?/login'); } function settings(){ $message = false; if($_POST){ if ($this->cache_exists($_POST['cache_type'])) { $message = '保存成功'; config('cache_type', $_POST['cache_type']); } else { $message = '缓存类型不可用,请确认已经安装了该拓展。'; config('cache_type', 'secache'); } //判断不渲染目录是否为全部不渲染 if($_POST['except_path']){ $except_path=(strcmp($_POST['except_path'],'all')==0?'all':get_absolute_path($_POST['except_path'])); }else{ $except_path=''; } config('site_name', $_POST['site_name']); config('style', $_POST['style']); config('onedrive_root', get_absolute_path($_POST['onedrive_root'])); config('except_path',$except_path); config('onedrive_hide', $_POST['onedrive_hide']); config('onedrive_hotlink', $_POST['onedrive_hotlink']); config('cache_expire_time', intval($_POST['cache_expire_time'])); $_POST['root_path'] = empty($_POST['root_path'])?'?':''; config('root_path', $_POST['root_path']); } $config = config('@base'); return view::load('settings')->with('config', $config)->with('message', $message); } function offline(){ if($_POST){ $config['offline'] = empty($_POST['offline'])?false:true; $config['online'] = empty($_POST['online'])?false:true; $config['upload_path'] = empty($_POST['upload_path']) ? '/' : get_absolute_path($_POST['upload_path']); config('offline@base',$config); } $config = config('offline@base'); return view::load('offline')->with('config',$config); } /** * 判断缓存类型 * * @param string $cache_type 缓存类型 * @return void */ function cache_exists($cache_type){ // 需要判断环境的缓存类型 $_cache_type = [ 'redis', 'memcache', ]; if (in_array($cache_type, $_cache_type)) { return class_exists(ucfirst($cache_type)); } return true; } function cache(){ if(!is_null($_POST['clear'])){ cache::clear(); $message = "清除缓存成功"; }elseif ( !is_null($_POST['refresh']) ){ oneindex::refresh_cache(get_absolute_path(config('onedrive_root'))); $message = "重建缓存成功"; } return view::load('cache')->with('message', $message); } function images(){ if($_POST){ $config['home'] = empty($_POST['home'])?false:true; $config['public'] = empty($_POST['public'])?false:true; $config['exts'] = explode(" ", $_POST['exts']); config('images@base',$config); } $config = config('images@base'); return view::load('images')->with('config', $config);; } function show(){ if(!empty($_POST) ){ foreach($_POST as $n=>$ext){ $show[$n] = explode(' ', $ext); } config('show', $show); } $names = [ 'stream'=>'直接输出(<5M),走本服务器流量(stream)', 'image' =>'图片(image)', 'video'=>'Dplayer 视频(video)', 'video2'=>'Dplayer DASH 视频(video2)/个人版账户不支持', 'video5'=>'html5视频(video5)', 'audio'=>'音频播放(audio)', 'code'=>'文本/代码(code)', 'doc'=>'文档(doc)' ]; $show = config('show'); return view::load('show')->with('names', $names)->with('show', $show); } function setpass(){ if($_SERVER['REQUEST_METHOD'] == 'POST'){ if($_POST['old_pass'] == config('password')){ if($_POST['password'] == $_POST['password2']){ config('password', $_POST['password']); $message = "修改成功"; }else{ $message = "两次密码不一致,修改失败"; } }else{ $message = "原密码错误,修改失败"; } } return view::load('setpass')->with('message', $message); } function install(){ if(!empty($_GET['code'])){ return $this->install_3(); } switch ( intval($_GET['step']) ){ case 1: return $this->install_1(); case 2: return $this->install_2(); default: return $this->install_0(); } } function install_0(){ $check['php'] = version_compare(PHP_VERSION,'5.5.0','ge'); $check['curl'] = function_exists('curl_init'); $check['config'] = is_writable(ROOT.'config/'); $check['cache'] = is_writable(ROOT.'cache/'); return view::load('install/install_0')->with('title','系统安装') ->with('check', $check); } function install_1(){ if(!empty($_POST['client_secret']) && !empty($_POST['client_id']) && !empty($_POST['redirect_uri']) && !empty($_POST['area'])){ config('@base', self::$default_config); config('client_secret',$_POST['client_secret']); config('client_id',$_POST['client_id']); config('redirect_uri',$_POST['redirect_uri']); config('area',$_POST['area']); return view::direct('?step=2'); } if($_SERVER['HTTP_HOST'] == 'localhost'){ $redirect_uri = 'http://'.$_SERVER['HTTP_HOST'].get_absolute_path(dirname($_SERVER['PHP_SELF'])); }else{ // 非https,调用ju.tn中转 $redirect_uri = 'https://tool.mintimate.cn/oneindexM/'; } $ru = "https://developer.microsoft.com/en-us/graph/quick-start?appID=_appId_&appName=_appName_&redirectUrl={$redirect_uri}&platform=option-php"; $deepLink = "/quickstart/graphIO?publicClientSupport=false&appName=oneindex&redirectUrl={$redirect_uri}&allowImplicitFlow=false&ru=".urlencode($ru); $app_url = "https://apps.dev.microsoft.com/?deepLink=".urlencode($deepLink); return view::load('install/install_1')->with('title','系统安装') ->with('redirect_uri', $redirect_uri) ->with('app_url', $app_url); } function install_2(){ return view::load('install/install_2')->with('title','系统安装'); } function install_3(){ $data = onedrive::authorize($_GET['code']); if(!empty($data['refresh_token'])){ config('refresh_token',$data['refresh_token']); config('@token', $data); } return view::load('install/install_3')->with('refresh_token',$data['refresh_token']); } } ================================================ FILE: controller/CommonController.php ================================================ with('tip','管理员未授权使用'); } } //搜索 function search(){ if(is_login()){ if($_POST['keyword']){ $keyword=$_POST['keyword']; $items = onedrive::search($keyword); if(!$items){ return view::load('common/tips')->with('tip','没有找到与“'.$_POST['keyword'].'”有关的内容'); } $searchinfo['keyword']=$keyword; $searchinfo['count']=count($items); return view::load('common/search')->with('items',$items)->with('searchinfo',$searchinfo); }else{ return '参数错误'; } } else{ return '请登陆后尝试'; } } //新建文件夹 //post参数:uploadurl,当前url的路径 function create_folder(){ if(is_login()){ $urlinfo=parse_url($_POST['uploadurl']); if(stristr($_POST['uploadurl'],'?')){ $paths = explode('/', rawurldecode($urlinfo['query'])); }else{ $paths = explode('/', rawurldecode($urlinfo['path'])); } $paths=array_values($paths); $remotepath = get_absolute_path(join('/', $paths)); $data = onedrive::create_folder(str_replace('//','/',config('onedrive_root').$remotepath),$_POST['foldername']); oneindex::refresh_cache(get_absolute_path(config('onedrive_root'))); return $data; } else{ return '未登录无法新建文件夹'; } } //重命名 //post参数:name:新名称;itemid:itemid function rename(){ if(is_login()){ $newname=$_POST['name']; $itemid=$_POST['itemid']; $resp=onedrive::rename($itemid,$newname); oneindex::refresh_cache(get_absolute_path(config('onedrive_root'))); return $resp; } else{ return '未登录无法重命名'; } } //删除 //传入一个stringfy后的itemid的数组 function deleteitems(){ if(is_login()){ $data = file_get_contents( "php://input" ); $items = json_decode( $data ); $resp=onedrive::delete($items); oneindex::refresh_cache(get_absolute_path(config('onedrive_root'))); return $resp; } else{ return '未登录无法删除'; } } //url上传 function upload_url(){ if(is_login()){ if($_POST['file_url']&&$_POST['path_url']){ $file_url=$_POST['file_url']; $path_url=$_POST['path_url']; if($_POST['file_name']){ $file_name = $_POST['file_name']; } else{ $file_name = pathinfo(parse_url($file_url,PHP_URL_PATH),PATHINFO_BASENAME); } $path = str_replace('//','/',$this->url2path($path_url).'/'.$file_name); $process_url = onedrive::upload_url($path , $file_url); if($process_url){ return $process_url; } else{ return 0; } }else{ return '参数错误'; } }else{ return '未登录'; } } //在线上传,大小限制在4M //post参数:onlinefile:一个文件;uploadurl:当前url路径 function onlinefileupload() { if($this->uploadcondition($_FILES["onlinefile"]) ){ $filename = $_FILES["onlinefile"]['name']; $content = file_get_contents( $_FILES["onlinefile"]['tmp_name']); //管理员不受上传目录限制 if(is_login()){ //获取路径 $paths = explode('/', rawurldecode($_POST['uploadurl'])); if(strcmp($paths[1],'?')==0){ array_shift($paths); array_shift($paths); } //$paths=array_shift($paths); $remotepath = get_absolute_path(join('/', $paths)); } //游客只能上传到指定目录 else{ $remotepath = config('offline')['upload_path']; } $remotefile = $remotepath.$filename; $result = onedrive::upload(str_replace('//','/',config('onedrive_root').$remotefile), $content); if($result){ $root = get_absolute_path(dirname($_SERVER['SCRIPT_NAME'])).config('root_path'); $http_type = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://'; $url = $_SERVER['HTTP_HOST'].$root.'/'.$remotepath.rawurldecode($filename).((config('root_path') == '?')?'&s':'?s'); $url = $http_type.str_replace('//','/', $url); $result['path']=$url; // view::direct($url); return json_encode($result); } }else{ return '未登录或文件过大'; } } //上传文件的条件判断 function uploadcondition($file){ if($file['size'] > 4485760 || $file['size'] == 0){ return false; } if(config('offline')['online']==false&&!is_login()){ return false; } return true; } //粘贴 function paste(){ if(is_login()){ $data = file_get_contents( "php://input" ); $jsondata = json_decode($data);//字符串转对象。 if($jsondata->cutitems){ $cutitems=$jsondata->cutitems; $url=$jsondata->url; return $this->cut($cutitems,$url); } if($jsondata->copyitems){ $copyitems=$jsondata->copyitems; $url=$jsondata->url; return $this->copy($copyitems,$url); } return '操作失误,请重新尝试!'; } else{ return '未登录无法重命名'; } } //移动或剪切 function cut($cutitems,$url){ $itemid=$this->url2id($url); $resp=onedrive::move($cutitems,$itemid); oneindex::refresh_cache(get_absolute_path(config('onedrive_root'))); return json_encode(json_decode(json_encode($resp)));//decode去掉字符串中的转义字符再 } //复制 function copy($copyitems,$url){ $itemid=$this->url2id($url); $resp=onedrive::copy($copyitems,$itemid); oneindex::refresh_cache(get_absolute_path(config('onedrive_root'))); return $resp; } //url转路径 function url2path($url){ $paths=array(); $urlinfo=parse_url($url); if(stristr($url,'?')){ $paths = explode('/', rawurldecode($urlinfo['query'])); }else{ $paths = explode('/', rawurldecode($urlinfo['path'])); } if(strcmp($paths[1],'?')==0){ array_shift($paths); array_shift($paths); } $remotepath = get_absolute_path(join('/', $paths)); $path = str_replace('//','/',config('onedrive_root').$remotepath); return $path; } //url转id function url2id($url){ $urlinfo=parse_url($url); if(stristr($url,'?')){ $paths = explode('/', rawurldecode($urlinfo['query'])); }else{ $paths = explode('/', rawurldecode($urlinfo['path'])); } $paths=array_values($paths); $totalpath = str_replace('//','/',config('onedrive_root').get_absolute_path(join('/', $paths))); $itemid=onedrive::path2id($totalpath); return $itemid; } } ================================================ FILE: controller/ImagesController.php ================================================ is_image($_FILES["file"]) ){ $filename = $_FILES["file"]['name']; $content = file_get_contents( $_FILES["file"]['tmp_name']); $remotepath = 'images/'.date('Y/m/d/').$this->generateRandomString(10).'/'; $remotefile = $remotepath.$filename; $result = onedrive::upload(config('onedrive_root').$remotefile, $content); if($result){ $root = get_absolute_path(dirname($_SERVER['SCRIPT_NAME'])).config('root_path'); $http_type = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://'; $url = $_SERVER['HTTP_HOST'].$root.'/'.$remotepath.rawurldecode($filename).((config('root_path') == '?')?'&s':'?s'); $url = $http_type.str_replace('//','/', $url); view::direct($url); } } return view::load('images/index'); } function is_image($file){ $config = config('images@base'); $ext = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)); if(!in_array($ext,$config['exts'])){ return false; } if($file['size'] > 10485760 || $file['size'] == 0){ return false; } return true; } } ================================================ FILE: controller/IndexController.php ================================================ name = array_pop($paths); } $this->url_path = get_absolute_path(join('/', $paths)); $this->path = get_absolute_path(config('onedrive_root').$this->url_path); //获取文件夹下所有元素 $this->items = $this->items($this->path); } function index(){ //是否404 $this->is404(); $this->is_password(); header("Expires:-1"); header("Cache-Control:no_cache"); header("Pragma:no-cache"); if(!empty($this->name)){//file return $this->file(); }else{//dir return $this->dir(); } } //判断是否加密 function is_password(){ if(empty($this->items['.password'])){ return false; }else{ $this->items['.password']['path'] = get_absolute_path($this->path).'.password'; } $password = $this->get_content($this->items['.password']); list($password) = explode("\n",$password); $password = trim($password); unset($this->items['.password']); if(!empty($password) && strcmp($password, $_COOKIE[md5($this->path)]) === 0||$_COOKIE['admin'] == md5(config('password').config('refresh_token'))){ return true; } $this->password($password); } function password($password){ if(!empty($_POST['password']) && strcmp($password, $_POST['password']) === 0){ setcookie(md5($this->path), $_POST['password']); return true; } $navs = $this->navs(); echo view::load('password')->with('navs',$navs); exit(); } //文件 function file(){ $item = $this->items[$this->name]; if ($item['folder']) {//是文件夹 $url = $_SERVER['REQUEST_URI'].'/'; }elseif(!is_null($_GET['t']) ){//缩略图 $url = $this->thumbnail($item); }elseif($_SERVER['REQUEST_METHOD'] == 'POST' || !is_null($_GET['s']) ){ return $this->show($item); }else{//返回下载链接 $url = $item['downloadUrl']; } header('Location: '.$url); } //文件夹 function dir(){ $root = get_absolute_path(dirname($_SERVER['SCRIPT_NAME'])).config('root_path'); $navs = $this->navs(); //以'/'拆分路径,并重新连接 $except_paths_buffer = explode('/', config('except_path')); $except_path_buffer = get_absolute_path(join('/', $except_paths_buffer)); $upload_paths_buffer = explode('/', config('offline')['upload_path']); $upload_path_buffer = get_absolute_path(join('/', $upload_paths_buffer)); $online = config('offline')['online']; //定义变脸,表示是否渲染此目录下的文件 $iscolorbar = true; //不渲染设置为all,或者当前路径与指定不渲染路径相同,则不渲染。如果设置为空,则渲染 if(strcmp(config('except_path'),'all')==0||strcmp(get_absolute_path($this->path), get_absolute_path(config('onedrive_root').$except_path_buffer))==0){ $iscolorbar = false; }else if(empty(config('except_path'))){ $iscolorbar = true; } //指定的游客在线上传路径是否和当前路径一致,相同则不渲染。 if(strcmp(get_absolute_path($this->path),get_absolute_path(config('onedrive_root').$upload_path_buffer))==0){ $iscolorbar = false; } if($iscolorbar) { if($this->items['index.html']){ $this->items['index.html']['path'] = get_absolute_path($this->path).'index.html'; $index = $this->get_content($this->items['index.html']); header('Content-type: text/html'); echo $index; exit(); } if($this->items['README.md']){ $this->items['README.md']['path'] = get_absolute_path($this->path).'README.md'; $readme = $this->get_content($this->items['README.md']); $Parsedown = new Parsedown(); $readme = $Parsedown->text($readme); //不在列表中展示 unset($this->items['README.md']); } if($this->items['HEAD.md']){ $this->items['HEAD.md']['path'] = get_absolute_path($this->path).'HEAD.md'; $head = $this->get_content($this->items['HEAD.md']); $Parsedown = new Parsedown(); $head = $Parsedown->text($head); //不在列表中展示 unset($this->items['HEAD.md']); } } //在线上传条件,后台开启或者登陆为管理员 if(config('offline')['online']||is_login()){ $manager['online']=true; } else{ $manager['online']=false; } if(config('offline')['offline']||is_login()){ $manager['offline']=true; }else{ $manager['offline']=false; } if(is_login()){ $manager['create_folder']=true; }else{ $manager['create_folder']=false; } return view::load('list')->with('title', empty(str_replace("/","",urldecode($this->url_path)))?"根目录":str_replace("/","",urldecode($this->url_path))) ->with('navs', $navs) ->with('path',join("/", array_map("rawurlencode", explode("/", $this->url_path))) ) ->with('root', $root) ->with('items', $this->items) ->with('head',$head) ->with('readme',$readme) ->with('manager',$manager); } function show($item){ $root = get_absolute_path(dirname($_SERVER['SCRIPT_NAME'])).(config('root_path')?'?/':''); $ext = strtolower(pathinfo($item['name'], PATHINFO_EXTENSION)); $data['title'] = $item['name']; $data['navs'] = $this->navs(); $data['item'] = $item; $data['ext'] = $ext; $data['item']['path'] = get_absolute_path($this->path).$this->name; $http_type = ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')) ? 'https://' : 'http://'; $uri = onedrive::urlencode(get_absolute_path($this->url_path.'/'.$this->name)); $data['url'] = $http_type.$_SERVER['HTTP_HOST'].$root.$uri; $show = config('show'); foreach($show as $n=>$exts){ if(in_array($ext,$exts)){ return view::load('show/'.$n)->with($data); } } header('Location: '.$item['downloadUrl']); } //缩略图 function thumbnail($item){ if(!empty($_GET['t'])){ list($width, $height) = explode('|', $_GET['t']); }else{ //800 176 96 $width = $height = 800; } $item['thumb'] = onedrive::thumbnail($this->path.$this->name); list($item['thumb'],$tmp) = explode('&width=', $item['thumb']); $item['thumb'] .= strpos($item['thumb'], '?')?'&':'?'; return $item['thumb']."width={$width}&height={$height}"; } //文件夹下元素 function items($path, $fetch=false){ $items = cache::get('dir_'.$this->path, function(){ return onedrive::dir($this->path); }, config('cache_expire_time')); return $items; } function navs(){ $root = get_absolute_path(dirname($_SERVER['SCRIPT_NAME'])).config('root_path'); $navs['/'] = get_absolute_path($root.'/'); foreach(explode('/',$this->url_path) as $v){ if(empty($v)){ continue; } $navs[rawurldecode($v)] = end($navs).$v.'/'; } if(!empty($this->name)){ $navs[$this->name] = end($navs).urlencode($this->name); } return $navs; } static function get_content($item){ $content = cache::get('content_'.$item['path'], function() use ($item){ $resp = fetch::get($item['downloadUrl']); if($resp->http_code == 200){ return $resp->content; } }, config('cache_expire_time') ); return $content; } //时候404 function is404(){ if(!empty($this->items[$this->name]) || (empty($this->name) && is_array($this->items)) ){ return false; } http_response_code(404); view::load('404')->show(); die(); } function __destruct(){ if (!function_exists("fastcgi_finish_request")) { return; } } } ================================================ FILE: controller/UploadController.php ================================================ add_task($local, $remotepath); $message = "文件".$local."已添加到队列"; }elseif(is_dir($local)){ $this->scan_dir($local, $remotepath); $message = "文件夹".$local."已添加到队列"; }elseif($local == realpath('.')){ $message = "因为安全原因,程序文件夹根目录不能上传"; }else{ $message = "文件不存在"; } $request = $this->task_request(); $request['url'] = substr($request['url'],0,-4).'run'; fetch::post($request); }elseif(!empty($_POST['begin_task'])){ $this->task($_POST['begin_task']); }elseif(!empty($_POST['delete_task'])){ unset($_POST['delete_task']); config('@upload', (array)$uploads); }elseif(!empty($_POST['empty_uploaded'])){ config('@uploaded', array()); } $uploading = config('@upload'); $uploaded = array_reverse((array)config('@uploaded')); return view::load('upload')->with('uploading', $uploading)->with('uploaded', $uploaded)->with('message', $message); } //扫描文件夹,添加到任务队列 private function scan_dir($localpath, $remotepath){ $files = scandir($localpath); foreach ($files as $file) { if ($file == '.' || $file == '..') { continue; } if (is_dir($localpath . '/' . $file)) { $this->scan_dir($localpath . '/' . $file, $remotepath.$file.'/'); }else{ $localfile = realpath($localpath . '/' . $file); $remotefile = $remotepath.$file; $this->add_task($localfile, $remotefile); } } } private function add_task($localfile, $remotefile){ $task = array( 'localfile'=>$localfile, 'remotepath' => $remotefile, 'filesize'=>onedrive::_filesize($localfile), 'upload_type'=>'web', 'update_time'=>0, ); $uploads = (array)config('@upload'); if(empty($uploads[$remotefile])){ $uploads[$remotefile] = $task; config('@upload', $uploads); } } //运行队列中的任务 function run(){ $uploads = (array)config('@upload'); $time = time(); $runing = 0; foreach($uploads as $task){ if($time < ($task['update_time']+60) AND $task['type']=='web' ){ $runing = $runing +1; } if($runing > 5)break; } foreach($uploads as $remotepath=>$task){ if($time < ($task['update_time']+60) OR !is_array($task) ){ continue; } $runing = $runing +1; print $remotepath.PHP_EOL; fetch::post($this->task_request($remotepath)); if($runing > 5)break; } if(count($uploads) > 5){ set_time_limit(100); sleep(60); $request = $this->task_request(); $request['url'] = substr($request['url'],0,-4).'run'; fetch::get($request); } } private function task_request($remotepath=''){ $request['headers'] = "Cookie: admin=".md5(config('password').config('refresh_token')).PHP_EOL; $request['headers'] .= "Host: ".$_SERVER['HTTP_HOST']; $request['curl_opt']=[CURLOPT_CONNECTTIMEOUT => 1,CURLOPT_TIMEOUT=>1,CURLOPT_FOLLOWLOCATION=>true]; $http_type = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') ? 'https://' : 'http://'; $request['url'] = $http_type.'127.0.0.1'.get_absolute_path(dirname($_SERVER['PHP_SELF'])).'?/admin/upload/task'; $request['post_data'] = 'remotepath='.urlencode($remotepath); return $request; } //执行任务 function task($remotepath=null){ $remotepath = is_null($remotepath)?$_POST['remotepath']:$remotepath; //file_put_contents('log.txt',$remotepath.PHP_EOL, FILE_APPEND); $uploads = config('@upload'); $task = $uploads[$remotepath]; if(empty($task)){ return; } if($task['filesize'] < 10485760){ @onedrive::upload($task['remotepath'], file_get_contents($task['localfile'])); unset($uploads[$remotepath]); config('@upload', (array)$uploads); config($remotepath.'@uploaded','success'); }else{ $uploads[$remotepath]['update_time'] = time(); config('@upload', (array)$uploads); $this->upload_large_file($task); } } function upload_large_file($task){ //创建上传会话 if(empty($task['url'])){ $data = onedrive::create_upload_session($task['remotepath']); if(!empty($data['uploadUrl'])){ $task['url'] = $data['uploadUrl']; $task['offset'] = 0; $task['length'] = 327680; $task['update_time'] = time(); config($task['remotepath'].'@upload',$task); }elseif ( $data === false ){ $uploads = config('@upload'); unset($uploads[$task['remotepath']]); config('@upload', $uploads); config($task['remotepath'].'@uploaded','exists'); } }else{ $begin_time = microtime(true); set_time_limit(0); $data = onedrive::upload_session($task['url'], $task['localfile'], $task['offset'], $task['length']); if(!empty($data['nextExpectedRanges'])){ //继续上传 $upload_time = microtime(true) - $begin_time; $task['speed'] = $task['length']/$upload_time; $task['length'] = intval($task['length']/$upload_time/32768*2)*327680; $task['length'] = ($task['length']>104857600)?104857600:$task['length']; list($offset, $filesize) = explode('-',$data['nextExpectedRanges'][0]); $task['offset'] = intval($offset); $info['update_time'] = time(); config($task['remotepath'].'@upload',$task); }elseif(!empty($data['@content.downloadUrl']) || !empty($data['id'])){ //上传完成 unset($uploads[$task['remotepath']]); config('@upload', $uploads); config($task['remotepath'].'@uploaded','success'); return; }else{ //失败,重新获取信息 echo "re get url"; $data = onedrive::upload_session_status($task['url']); if(empty($data)|| $info['length']<100){ onedrive::delete_upload_session($task['url']); unset($task['url']); config($task['remotepath'].'@upload', $task); }elseif(!empty($data['nextExpectedRanges'])){ list($offset, $filesize) = explode('-',$data['nextExpectedRanges'][0]); $task['offset'] = intval($offset); $task['length'] = $task['length']/1.5; config($task['remotepath'].'@upload', $task); } } } $request= $this->task_request($task['remotepath']); $resp = fetch::post($request); //var_dump($resp); } } ================================================ FILE: index.php ================================================ DefinitionData = array(); # standardize line breaks $text = str_replace(array("\r\n", "\r"), "\n", $text); # remove surrounding line breaks $text = trim($text, "\n"); # split text into lines $lines = explode("\n", $text); # iterate through lines to identify blocks $markup = $this->lines($lines); # trim line breaks $markup = trim($markup, "\n"); return $markup; } # # Setters # function setBreaksEnabled($breaksEnabled) { $this->breaksEnabled = $breaksEnabled; return $this; } protected $breaksEnabled; function setMarkupEscaped($markupEscaped) { $this->markupEscaped = $markupEscaped; return $this; } protected $markupEscaped; function setUrlsLinked($urlsLinked) { $this->urlsLinked = $urlsLinked; return $this; } protected $urlsLinked = true; function setSafeMode($safeMode) { $this->safeMode = (bool) $safeMode; return $this; } protected $safeMode; protected $safeLinksWhitelist = array( 'http://', 'https://', 'ftp://', 'ftps://', 'mailto:', 'data:image/png;base64,', 'data:image/gif;base64,', 'data:image/jpeg;base64,', 'irc:', 'ircs:', 'git:', 'ssh:', 'news:', 'steam:', ); # # Lines # protected $BlockTypes = array( '#' => array('Header'), '*' => array('Rule', 'List'), '+' => array('List'), '-' => array('SetextHeader', 'Table', 'Rule', 'List'), '0' => array('List'), '1' => array('List'), '2' => array('List'), '3' => array('List'), '4' => array('List'), '5' => array('List'), '6' => array('List'), '7' => array('List'), '8' => array('List'), '9' => array('List'), ':' => array('Table'), '<' => array('Comment', 'Markup'), '=' => array('SetextHeader'), '>' => array('Quote'), '[' => array('Reference'), '_' => array('Rule'), '`' => array('FencedCode'), '|' => array('Table'), '~' => array('FencedCode'), ); # ~ protected $unmarkedBlockTypes = array( 'Code', ); # # Blocks # protected function lines(array $lines) { $CurrentBlock = null; foreach ($lines as $line) { if (chop($line) === '') { if (isset($CurrentBlock)) { $CurrentBlock['interrupted'] = true; } continue; } if (strpos($line, "\t") !== false) { $parts = explode("\t", $line); $line = $parts[0]; unset($parts[0]); foreach ($parts as $part) { $shortage = 4 - mb_strlen($line, 'utf-8') % 4; $line .= str_repeat(' ', $shortage); $line .= $part; } } $indent = 0; while (isset($line[$indent]) and $line[$indent] === ' ') { $indent ++; } $text = $indent > 0 ? substr($line, $indent) : $line; # ~ $Line = array('body' => $line, 'indent' => $indent, 'text' => $text); # ~ if (isset($CurrentBlock['continuable'])) { $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); if (isset($Block)) { $CurrentBlock = $Block; continue; } else { if ($this->isBlockCompletable($CurrentBlock['type'])) { $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); } } } # ~ $marker = $text[0]; # ~ $blockTypes = $this->unmarkedBlockTypes; if (isset($this->BlockTypes[$marker])) { foreach ($this->BlockTypes[$marker] as $blockType) { $blockTypes []= $blockType; } } # # ~ foreach ($blockTypes as $blockType) { $Block = $this->{'block'.$blockType}($Line, $CurrentBlock); if (isset($Block)) { $Block['type'] = $blockType; if ( ! isset($Block['identified'])) { $Blocks []= $CurrentBlock; $Block['identified'] = true; } if ($this->isBlockContinuable($blockType)) { $Block['continuable'] = true; } $CurrentBlock = $Block; continue 2; } } # ~ if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) { $CurrentBlock['element']['text'] .= "\n".$text; } else { $Blocks []= $CurrentBlock; $CurrentBlock = $this->paragraph($Line); $CurrentBlock['identified'] = true; } } # ~ if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) { $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); } # ~ $Blocks []= $CurrentBlock; unset($Blocks[0]); # ~ $markup = ''; foreach ($Blocks as $Block) { if (isset($Block['hidden'])) { continue; } $markup .= "\n"; $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']); } $markup .= "\n"; # ~ return $markup; } protected function isBlockContinuable($Type) { return method_exists($this, 'block'.$Type.'Continue'); } protected function isBlockCompletable($Type) { return method_exists($this, 'block'.$Type.'Complete'); } # # Code protected function blockCode($Line, $Block = null) { if (isset($Block) and ! isset($Block['type']) and ! isset($Block['interrupted'])) { return; } if ($Line['indent'] >= 4) { $text = substr($Line['body'], 4); $Block = array( 'element' => array( 'name' => 'pre', 'handler' => 'element', 'text' => array( 'name' => 'code', 'text' => $text, ), ), ); return $Block; } } protected function blockCodeContinue($Line, $Block) { if ($Line['indent'] >= 4) { if (isset($Block['interrupted'])) { $Block['element']['text']['text'] .= "\n"; unset($Block['interrupted']); } $Block['element']['text']['text'] .= "\n"; $text = substr($Line['body'], 4); $Block['element']['text']['text'] .= $text; return $Block; } } protected function blockCodeComplete($Block) { $text = $Block['element']['text']['text']; $Block['element']['text']['text'] = $text; return $Block; } # # Comment protected function blockComment($Line) { if ($this->markupEscaped or $this->safeMode) { return; } if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') { $Block = array( 'markup' => $Line['body'], ); if (preg_match('/-->$/', $Line['text'])) { $Block['closed'] = true; } return $Block; } } protected function blockCommentContinue($Line, array $Block) { if (isset($Block['closed'])) { return; } $Block['markup'] .= "\n" . $Line['body']; if (preg_match('/-->$/', $Line['text'])) { $Block['closed'] = true; } return $Block; } # # Fenced Code protected function blockFencedCode($Line) { if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([^`]+)?[ ]*$/', $Line['text'], $matches)) { $Element = array( 'name' => 'code', 'text' => '', ); if (isset($matches[1])) { $class = 'language-'.$matches[1]; $Element['attributes'] = array( 'class' => $class, ); } $Block = array( 'char' => $Line['text'][0], 'element' => array( 'name' => 'pre', 'handler' => 'element', 'text' => $Element, ), ); return $Block; } } protected function blockFencedCodeContinue($Line, $Block) { if (isset($Block['complete'])) { return; } if (isset($Block['interrupted'])) { $Block['element']['text']['text'] .= "\n"; unset($Block['interrupted']); } if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) { $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1); $Block['complete'] = true; return $Block; } $Block['element']['text']['text'] .= "\n".$Line['body']; return $Block; } protected function blockFencedCodeComplete($Block) { $text = $Block['element']['text']['text']; $Block['element']['text']['text'] = $text; return $Block; } # # Header protected function blockHeader($Line) { if (isset($Line['text'][1])) { $level = 1; while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') { $level ++; } if ($level > 6) { return; } $text = trim($Line['text'], '# '); $Block = array( 'element' => array( 'name' => 'h' . min(6, $level), 'text' => $text, 'handler' => 'line', ), ); return $Block; } } # # List protected function blockList($Line) { list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) { $Block = array( 'indent' => $Line['indent'], 'pattern' => $pattern, 'element' => array( 'name' => $name, 'handler' => 'elements', ), ); if($name === 'ol') { $listStart = stristr($matches[0], '.', true); if($listStart !== '1') { $Block['element']['attributes'] = array('start' => $listStart); } } $Block['li'] = array( 'name' => 'li', 'handler' => 'li', 'text' => array( $matches[2], ), ); $Block['element']['text'] []= & $Block['li']; return $Block; } } protected function blockListContinue($Line, array $Block) { if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) { if (isset($Block['interrupted'])) { $Block['li']['text'] []= ''; $Block['loose'] = true; unset($Block['interrupted']); } unset($Block['li']); $text = isset($matches[1]) ? $matches[1] : ''; $Block['li'] = array( 'name' => 'li', 'handler' => 'li', 'text' => array( $text, ), ); $Block['element']['text'] []= & $Block['li']; return $Block; } if ($Line['text'][0] === '[' and $this->blockReference($Line)) { return $Block; } if ( ! isset($Block['interrupted'])) { $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); $Block['li']['text'] []= $text; return $Block; } if ($Line['indent'] > 0) { $Block['li']['text'] []= ''; $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); $Block['li']['text'] []= $text; unset($Block['interrupted']); return $Block; } } protected function blockListComplete(array $Block) { if (isset($Block['loose'])) { foreach ($Block['element']['text'] as &$li) { if (end($li['text']) !== '') { $li['text'] []= ''; } } } return $Block; } # # Quote protected function blockQuote($Line) { if (preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) { $Block = array( 'element' => array( 'name' => 'blockquote', 'handler' => 'lines', 'text' => (array) $matches[1], ), ); return $Block; } } protected function blockQuoteContinue($Line, array $Block) { if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) { if (isset($Block['interrupted'])) { $Block['element']['text'] []= ''; unset($Block['interrupted']); } $Block['element']['text'] []= $matches[1]; return $Block; } if ( ! isset($Block['interrupted'])) { $Block['element']['text'] []= $Line['text']; return $Block; } } # # Rule protected function blockRule($Line) { if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text'])) { $Block = array( 'element' => array( 'name' => 'hr' ), ); return $Block; } } # # Setext protected function blockSetextHeader($Line, array $Block = null) { if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) { return; } if (chop($Line['text'], $Line['text'][0]) === '') { $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; return $Block; } } # # Markup protected function blockMarkup($Line) { if ($this->markupEscaped or $this->safeMode) { return; } if (preg_match('/^<(\w[\w-]*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches)) { $element = strtolower($matches[1]); if (in_array($element, $this->textLevelElements)) { return; } $Block = array( 'name' => $matches[1], 'depth' => 0, 'markup' => $Line['text'], ); $length = strlen($matches[0]); $remainder = substr($Line['text'], $length); if (trim($remainder) === '') { if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) { $Block['closed'] = true; $Block['void'] = true; } } else { if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) { return; } if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) { $Block['closed'] = true; } } return $Block; } } protected function blockMarkupContinue($Line, array $Block) { if (isset($Block['closed'])) { return; } if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open { $Block['depth'] ++; } if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close { if ($Block['depth'] > 0) { $Block['depth'] --; } else { $Block['closed'] = true; } } if (isset($Block['interrupted'])) { $Block['markup'] .= "\n"; unset($Block['interrupted']); } $Block['markup'] .= "\n".$Line['body']; return $Block; } # # Reference protected function blockReference($Line) { if (preg_match('/^\[(.+?)\]:[ ]*?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches)) { $id = strtolower($matches[1]); $Data = array( 'url' => $matches[2], 'title' => null, ); if (isset($matches[3])) { $Data['title'] = $matches[3]; } $this->DefinitionData['Reference'][$id] = $Data; $Block = array( 'hidden' => true, ); return $Block; } } # # Table protected function blockTable($Line, array $Block = null) { if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) { return; } if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') { $alignments = array(); $divider = $Line['text']; $divider = trim($divider); $divider = trim($divider, '|'); $dividerCells = explode('|', $divider); foreach ($dividerCells as $dividerCell) { $dividerCell = trim($dividerCell); if ($dividerCell === '') { continue; } $alignment = null; if ($dividerCell[0] === ':') { $alignment = 'left'; } if (substr($dividerCell, - 1) === ':') { $alignment = $alignment === 'left' ? 'center' : 'right'; } $alignments []= $alignment; } # ~ $HeaderElements = array(); $header = $Block['element']['text']; $header = trim($header); $header = trim($header, '|'); $headerCells = explode('|', $header); foreach ($headerCells as $index => $headerCell) { $headerCell = trim($headerCell); $HeaderElement = array( 'name' => 'th', 'text' => $headerCell, 'handler' => 'line', ); if (isset($alignments[$index])) { $alignment = $alignments[$index]; $HeaderElement['attributes'] = array( 'style' => 'text-align: '.$alignment.';', ); } $HeaderElements []= $HeaderElement; } # ~ $Block = array( 'alignments' => $alignments, 'identified' => true, 'element' => array( 'name' => 'table', 'handler' => 'elements', ), ); $Block['element']['text'] []= array( 'name' => 'thead', 'handler' => 'elements', ); $Block['element']['text'] []= array( 'name' => 'tbody', 'handler' => 'elements', 'text' => array(), ); $Block['element']['text'][0]['text'] []= array( 'name' => 'tr', 'handler' => 'elements', 'text' => $HeaderElements, ); return $Block; } } protected function blockTableContinue($Line, array $Block) { if (isset($Block['interrupted'])) { return; } if ($Line['text'][0] === '|' or strpos($Line['text'], '|')) { $Elements = array(); $row = $Line['text']; $row = trim($row); $row = trim($row, '|'); preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches); foreach ($matches[0] as $index => $cell) { $cell = trim($cell); $Element = array( 'name' => 'td', 'handler' => 'line', 'text' => $cell, ); if (isset($Block['alignments'][$index])) { $Element['attributes'] = array( 'style' => 'text-align: '.$Block['alignments'][$index].';', ); } $Elements []= $Element; } $Element = array( 'name' => 'tr', 'handler' => 'elements', 'text' => $Elements, ); $Block['element']['text'][1]['text'] []= $Element; return $Block; } } # # ~ # protected function paragraph($Line) { $Block = array( 'element' => array( 'name' => 'p', 'text' => $Line['text'], 'handler' => 'line', ), ); return $Block; } # # Inline Elements # protected $InlineTypes = array( '"' => array('SpecialCharacter'), '!' => array('Image'), '&' => array('SpecialCharacter'), '*' => array('Emphasis'), ':' => array('Url'), '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'), '>' => array('SpecialCharacter'), '[' => array('Link'), '_' => array('Emphasis'), '`' => array('Code'), '~' => array('Strikethrough'), '\\' => array('EscapeSequence'), ); # ~ protected $inlineMarkerList = '!"*_&[:<>`~\\'; # # ~ # public function line($text, $nonNestables=array()) { $markup = ''; # $excerpt is based on the first occurrence of a marker while ($excerpt = strpbrk($text, $this->inlineMarkerList)) { $marker = $excerpt[0]; $markerPosition = strpos($text, $marker); $Excerpt = array('text' => $excerpt, 'context' => $text); foreach ($this->InlineTypes[$marker] as $inlineType) { # check to see if the current inline type is nestable in the current context if ( ! empty($nonNestables) and in_array($inlineType, $nonNestables)) { continue; } $Inline = $this->{'inline'.$inlineType}($Excerpt); if ( ! isset($Inline)) { continue; } # makes sure that the inline belongs to "our" marker if (isset($Inline['position']) and $Inline['position'] > $markerPosition) { continue; } # sets a default inline position if ( ! isset($Inline['position'])) { $Inline['position'] = $markerPosition; } # cause the new element to 'inherit' our non nestables foreach ($nonNestables as $non_nestable) { $Inline['element']['nonNestables'][] = $non_nestable; } # the text that comes before the inline $unmarkedText = substr($text, 0, $Inline['position']); # compile the unmarked text $markup .= $this->unmarkedText($unmarkedText); # compile the inline $markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']); # remove the examined text $text = substr($text, $Inline['position'] + $Inline['extent']); continue 2; } # the marker does not belong to an inline $unmarkedText = substr($text, 0, $markerPosition + 1); $markup .= $this->unmarkedText($unmarkedText); $text = substr($text, $markerPosition + 1); } $markup .= $this->unmarkedText($text); return $markup; } # # ~ # protected function inlineCode($Excerpt) { $marker = $Excerpt['text'][0]; if (preg_match('/^('.$marker.'+)[ ]*(.+?)[ ]*(? strlen($matches[0]), 'element' => array( 'name' => 'code', 'text' => $text, ), ); } } protected function inlineEmailTag($Excerpt) { if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches)) { $url = $matches[1]; if ( ! isset($matches[2])) { $url = 'mailto:' . $url; } return array( 'extent' => strlen($matches[0]), 'element' => array( 'name' => 'a', 'text' => $matches[1], 'attributes' => array( 'href' => $url, ), ), ); } } protected function inlineEmphasis($Excerpt) { if ( ! isset($Excerpt['text'][1])) { return; } $marker = $Excerpt['text'][0]; if ($Excerpt['text'][1] === $marker and preg_match($this->StrongRegex[$marker], $Excerpt['text'], $matches)) { $emphasis = 'strong'; } elseif (preg_match($this->EmRegex[$marker], $Excerpt['text'], $matches)) { $emphasis = 'em'; } else { return; } return array( 'extent' => strlen($matches[0]), 'element' => array( 'name' => $emphasis, 'handler' => 'line', 'text' => $matches[1], ), ); } protected function inlineEscapeSequence($Excerpt) { if (isset($Excerpt['text'][1]) and in_array($Excerpt['text'][1], $this->specialCharacters)) { return array( 'markup' => $Excerpt['text'][1], 'extent' => 2, ); } } protected function inlineImage($Excerpt) { if ( ! isset($Excerpt['text'][1]) or $Excerpt['text'][1] !== '[') { return; } $Excerpt['text']= substr($Excerpt['text'], 1); $Link = $this->inlineLink($Excerpt); if ($Link === null) { return; } $Inline = array( 'extent' => $Link['extent'] + 1, 'element' => array( 'name' => 'img', 'attributes' => array( 'src' => $Link['element']['attributes']['href'], 'alt' => $Link['element']['text'], ), ), ); $Inline['element']['attributes'] += $Link['element']['attributes']; unset($Inline['element']['attributes']['href']); return $Inline; } protected function inlineLink($Excerpt) { $Element = array( 'name' => 'a', 'handler' => 'line', 'nonNestables' => array('Url', 'Link'), 'text' => null, 'attributes' => array( 'href' => null, 'title' => null, ), ); $extent = 0; $remainder = $Excerpt['text']; if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) { $Element['text'] = $matches[1]; $extent += strlen($matches[0]); $remainder = substr($remainder, $extent); } else { return; } if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*"|\'[^\']*\'))?\s*[)]/', $remainder, $matches)) { $Element['attributes']['href'] = $matches[1]; if (isset($matches[2])) { $Element['attributes']['title'] = substr($matches[2], 1, - 1); } $extent += strlen($matches[0]); } else { if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) { $definition = strlen($matches[1]) ? $matches[1] : $Element['text']; $definition = strtolower($definition); $extent += strlen($matches[0]); } else { $definition = strtolower($Element['text']); } if ( ! isset($this->DefinitionData['Reference'][$definition])) { return; } $Definition = $this->DefinitionData['Reference'][$definition]; $Element['attributes']['href'] = $Definition['url']; $Element['attributes']['title'] = $Definition['title']; } return array( 'extent' => $extent, 'element' => $Element, ); } protected function inlineMarkup($Excerpt) { if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) { return; } if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*[ ]*>/s', $Excerpt['text'], $matches)) { return array( 'markup' => $matches[0], 'extent' => strlen($matches[0]), ); } if ($Excerpt['text'][1] === '!' and preg_match('/^/s', $Excerpt['text'], $matches)) { return array( 'markup' => $matches[0], 'extent' => strlen($matches[0]), ); } if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches)) { return array( 'markup' => $matches[0], 'extent' => strlen($matches[0]), ); } } protected function inlineSpecialCharacter($Excerpt) { if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) { return array( 'markup' => '&', 'extent' => 1, ); } $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot'); if (isset($SpecialCharacter[$Excerpt['text'][0]])) { return array( 'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';', 'extent' => 1, ); } } protected function inlineStrikethrough($Excerpt) { if ( ! isset($Excerpt['text'][1])) { return; } if ($Excerpt['text'][1] === '~' and preg_match('/^~~(?=\S)(.+?)(?<=\S)~~/', $Excerpt['text'], $matches)) { return array( 'extent' => strlen($matches[0]), 'element' => array( 'name' => 'del', 'text' => $matches[1], 'handler' => 'line', ), ); } } protected function inlineUrl($Excerpt) { if ($this->urlsLinked !== true or ! isset($Excerpt['text'][2]) or $Excerpt['text'][2] !== '/') { return; } if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) { $url = $matches[0][0]; $Inline = array( 'extent' => strlen($matches[0][0]), 'position' => $matches[0][1], 'element' => array( 'name' => 'a', 'text' => $url, 'attributes' => array( 'href' => $url, ), ), ); return $Inline; } } protected function inlineUrlTag($Excerpt) { if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+:\/{2}[^ >]+)>/i', $Excerpt['text'], $matches)) { $url = $matches[1]; return array( 'extent' => strlen($matches[0]), 'element' => array( 'name' => 'a', 'text' => $url, 'attributes' => array( 'href' => $url, ), ), ); } } # ~ protected function unmarkedText($text) { if ($this->breaksEnabled) { $text = preg_replace('/[ ]*\n/', "
\n", $text); } else { $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "
\n", $text); $text = str_replace(" \n", "\n", $text); } return $text; } # # Handlers # protected function element(array $Element) { if ($this->safeMode) { $Element = $this->sanitiseElement($Element); } $markup = '<'.$Element['name']; if (isset($Element['attributes'])) { foreach ($Element['attributes'] as $name => $value) { if ($value === null) { continue; } $markup .= ' '.$name.'="'.self::escape($value).'"'; } } if (isset($Element['text'])) { $markup .= '>'; if (!isset($Element['nonNestables'])) { $Element['nonNestables'] = array(); } if (isset($Element['handler'])) { $markup .= $this->{$Element['handler']}($Element['text'], $Element['nonNestables']); } else { $markup .= self::escape($Element['text'], true); } $markup .= ''; } else { $markup .= ' />'; } return $markup; } protected function elements(array $Elements) { $markup = ''; foreach ($Elements as $Element) { $markup .= "\n" . $this->element($Element); } $markup .= "\n"; return $markup; } # ~ protected function li($lines) { $markup = $this->lines($lines); $trimmedMarkup = trim($markup); if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '

') { $markup = $trimmedMarkup; $markup = substr($markup, 3); $position = strpos($markup, "

"); $markup = substr_replace($markup, '', $position, 4); } return $markup; } # # Deprecated Methods # function parse($text) { $markup = $this->text($text); return $markup; } protected function sanitiseElement(array $Element) { static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/'; static $safeUrlNameToAtt = array( 'a' => 'href', 'img' => 'src', ); if (isset($safeUrlNameToAtt[$Element['name']])) { $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]); } if ( ! empty($Element['attributes'])) { foreach ($Element['attributes'] as $att => $val) { # filter out badly parsed attribute if ( ! preg_match($goodAttribute, $att)) { unset($Element['attributes'][$att]); } # dump onevent attribute elseif (self::striAtStart($att, 'on')) { unset($Element['attributes'][$att]); } } } return $Element; } protected function filterUnsafeUrlInAttribute(array $Element, $attribute) { foreach ($this->safeLinksWhitelist as $scheme) { if (self::striAtStart($Element['attributes'][$attribute], $scheme)) { return $Element; } } $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]); return $Element; } # # Static Methods # protected static function escape($text, $allowQuotes = false) { return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); } protected static function striAtStart($string, $needle) { $len = strlen($needle); if ($len > strlen($string)) { return false; } else { return strtolower(substr($string, 0, $len)) === strtolower($needle); } } static function instance($name = 'default') { if (isset(self::$instances[$name])) { return self::$instances[$name]; } $instance = new static(); self::$instances[$name] = $instance; return $instance; } private static $instances = array(); # # Fields # protected $DefinitionData; # # Read-Only protected $specialCharacters = array( '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', ); protected $StrongRegex = array( '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', '_' => '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', ); protected $EmRegex = array( '*' => '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', '_' => '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', ); protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; protected $voidElements = array( 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', ); protected $textLevelElements = array( 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', 'i', 'rp', 'del', 'code', 'strike', 'marquee', 'q', 'rt', 'ins', 'font', 'strong', 's', 'tt', 'kbd', 'mark', 'u', 'xm', 'sub', 'nobr', 'sup', 'ruby', 'var', 'span', 'wbr', 'time', ); } ================================================ FILE: lib/cache/filecache_.php ================================================ cache_path = $cache_path; } function get($key){ $file = $this->cache_path . md5($key) . '.php'; $data = @include $file; if( is_array($data) && $data['expire'] > time() && !is_null($data['data']) ){ return $data['data']; }else{ return null; } } function set($key, $value=null, $expire=99999999){ $file = $this->cache_path . md5($key) . '.php'; $data['expire'] = time() + $expire; $data['data'] = $value; return @file_put_contents($file, "cache_path.'*.php')); } } ================================================ FILE: lib/cache/memcache_.php ================================================ m = new Memcache(); if(empty($config)){ $config = 'localhost:11211'; } list($host, $port) = explode(':', $config, 2); $this->m->addServer($host, $port); } function get($key){ $data = $this->m->get($key); if( is_array($data) && $data['expire'] > time() && !is_null($data['data']) ){ return $data['data']; }else{ return null; } } function set($key, $value=null, $expire=99999999){ $data['expire'] = time() + $expire; $data['data'] = $value; return $this->m->set($key, $data); } function clear(){ $this->m->flush(10); } } ================================================ FILE: lib/cache/redis_.php ================================================ redis = new Redis(); if(empty($config)){ $config = 'localhost:6379'; } list($host, $port) = explode(':', $config, 2); $this->redis->pconnect($host, $port); } function get($key){ $gRefreshTime = $this->redis->get("OneIndex_gRefreshTime"); $key = "OneIndex_$gRefreshTime\_" . $key; $data = $this->redis->get($key); return unserialize($data) ?: null; } function set($key, $value=null, $expire=600){ $gRefreshTime = $this->redis->get("OneIndex_gRefreshTime"); if (empty($gRefreshTime)) { $gRefreshTime = time(); $this->redis->set("OneIndex_gRefreshTime", $gRefreshTime); } $key = "OneIndex_$gRefreshTime\_" . $key; return $this->redis->set($key, serialize($value), $expire); } function clear(){ $this->redis->set("OneIndex_gRefreshTime", $gRefreshTime); } } ================================================ FILE: lib/cache/secache_.php ================================================ cachefile = $cachefile; $this->c = new secache(); $this->c->workat($this->cachefile); } function get($key){ $this->c->fetch(md5($key),$data); if( is_array($data) && $data['expire'] > time() && !is_null($data['data']) ){ return $data['data']; }else{ return null; } } function set($key, $value=null, $expire=99999999){ $data['expire'] = time() + $expire; $data['data'] = $value; return $this->c->store(md5($key),$data); } function clear(){ return $this->c->clear(); } } class secache{ var $idx_node_size = 40; var $idx_node_base = 0; var $data_base_pos = 262588; //40+20+24*16+16*16*16*16*4; var $schema_item_size = 24; var $header_padding = 20; //保留空间 放置php标记防止下载 var $info_size = 20; //保留空间 4+16 maxsize|ver //40起 添加20字节保留区域 var $idx_seq_pos = 40; //id 计数器节点地址 var $dfile_cur_pos = 44; //id 计数器节点地址 var $idx_free_pos = 48; //id 空闲链表入口地址 var $idx_base_pos = 444; //40+20+24*16 var $min_size = 10240; //10M最小值 var $schema_struct = array('size','free','lru_head','lru_tail','hits','miss'); var $ver = '$Rev$'; var $name = '系统默认缓存(文件型)'; function workat($file){ $this->_file = $file.'.php'; $this->_bsize_list = array( 512=>10, 3<<10=>10, 8<<10=>10, 20<<10=>4, 30<<10=>2, 50<<10=>2, 80<<10=>2, 96<<10=>2, 128<<10=>2, 224<<10=>2, 256<<10=>2, 512<<10=>1, 1024<<10=>1, ); $this->_node_struct = array( 'next'=>array(0,'V'), 'prev'=>array(4,'V'), 'data'=>array(8,'V'), 'size'=>array(12,'V'), 'lru_right'=>array(16,'V'), 'lru_left'=>array(20,'V'), 'key'=>array(24,'H*'), ); if(!file_exists($this->_file)){ $this->create(); }else{ $this->_rs = fopen($this->_file,'rb+') or $this->trigger_error('Can\'t open the cachefile: '.realpath($this->_file),E_USER_ERROR); $this->_seek($this->header_padding); $info = unpack('V1max_size/a*ver',fread($this->_rs,$this->info_size)); $info['ver'] = trim($info['ver']); if($info['ver']!=$this->ver){ $this->_format(true); }else{ $this->max_size = $info['max_size']; } } $this->idx_node_base = $this->data_base_pos+$this->max_size; $this->_block_size_list = array_keys($this->_bsize_list); sort($this->_block_size_list); return true; } function create(){ $this->_rs = fopen($this->_file,'wb+') or $this->trigger_error('Can\'t open the cachefile: '.realpath($this->_file),E_USER_ERROR);; fseek($this->_rs,0); fputs($this->_rs,'<'.'?php exit()?'.'>'); return $this->_format(); } function _puts($offset,$data){ if($offset < $this->max_size*1.5){ $this->_seek($offset); return fputs($this->_rs,$data); }else{ $this->trigger_error('Offset over quota:'.$offset,E_USER_ERROR); } } function _seek($offset){ return fseek($this->_rs,$offset); } function clear(){ return $this->_format(true); } function fetch($key,&$return){ if($this->lock(false)){ $locked = true; } if($this->search($key,$offset)){ $info = $this->_get_node($offset); $schema_id = $this->_get_size_schema_id($info['size']); if($schema_id===false){ if($locked) $this->unlock(); return false; } $this->_seek($info['data']); $data = fread($this->_rs,$info['size']); $return = unserialize($data); if($return===false){ if($locked) $this->unlock(); return false; } if($locked){ $this->_lru_push($schema_id,$info['offset']); $this->_set_schema($schema_id,'hits',$this->_get_schema($schema_id,'hits')+1); return $this->unlock(); }else{ return true; } }else{ if($locked) $this->unlock(); return false; } } /** * lock * 如果flock不管用,请继承本类,并重载此方法 * * @param mixed $is_block 是否阻塞 * @access public * @return void */ function lock($is_block,$whatever=false){ ignore_user_abort(1); return flock($this->_rs, $is_block?LOCK_EX:LOCK_EX+LOCK_NB); } /** * unlock * 如果flock不管用,请继承本类,并重载此方法 * * @access public * @return void */ function unlock(){ ignore_user_abort(0); return flock($this->_rs, LOCK_UN); } function delete($key,$pos=false){ if($pos || $this->search($key,$pos)){ if($info = $this->_get_node($pos)){ //删除data区域 if($info['prev']){ $this->_set_node($info['prev'],'next',$info['next']); $this->_set_node($info['next'],'prev',$info['prev']); }else{ //改入口位置 $this->_set_node($info['next'],'prev',0); $this->_set_node_root($key,$info['next']); } $this->_free_dspace($info['size'],$info['data']); $this->_lru_delete($info); $this->_free_node($pos); return $info['prev']; } } return false; } function store($key,$value){ if($this->lock(true)){ //save data $data = serialize($value); $size = strlen($data); //get list_idx $has_key = $this->search($key,$list_idx_offset); $schema_id = $this->_get_size_schema_id($size); if($schema_id===false){ $this->unlock(); return false; } if($has_key){ $hdseq = $list_idx_offset; $info = $this->_get_node($hdseq); if($schema_id == $this->_get_size_schema_id($info['size'])){ $dataoffset = $info['data']; }else{ //破掉原有lru $this->_lru_delete($info); if(!($dataoffset = $this->_dalloc($schema_id))){ $this->unlock(); return false; } $this->_free_dspace($info['size'],$info['data']); $this->_set_node($hdseq,'lru_left',0); $this->_set_node($hdseq,'lru_right',0); } $this->_set_node($hdseq,'size',$size); $this->_set_node($hdseq,'data',$dataoffset); }else{ if(!($dataoffset = $this->_dalloc($schema_id))){ $this->unlock(); return false; } $hdseq = $this->_alloc_idx(array( 'next'=>0, 'prev'=>$list_idx_offset, 'data'=>$dataoffset, 'size'=>$size, 'lru_right'=>0, 'lru_left'=>0, 'key'=>$key, )); if($list_idx_offset>0){ $this->_set_node($list_idx_offset,'next',$hdseq); }else{ $this->_set_node_root($key,$hdseq); } } if($dataoffset>$this->max_size){ $this->trigger_error('alloc datasize:'.$dataoffset,E_USER_WARNING); return false; } $this->_puts($dataoffset,$data); $this->_set_schema($schema_id,'miss',$this->_get_schema($schema_id,'miss')+1); $this->_lru_push($schema_id,$hdseq); $this->unlock(); return true; }else{ $this->trigger_error("Couldn't lock the file !",E_USER_WARNING); return false; } } /** * search * 查找指定的key * 如果找到节点则$pos=节点本身 返回true * 否则 $pos=树的末端 返回false * * @param mixed $key * @access public * @return void */ function search($key,&$pos){ return $this->_get_pos_by_key($this->_get_node_root($key),$key,$pos); } function _get_size_schema_id($size){ foreach($this->_block_size_list as $k=>$block_size){ if($size <= $block_size){ return $k; } } return false; } function _parse_str_size($str_size,$default){ if(preg_match('/^([0-9]+)\s*([gmk]|)$/i',$str_size,$match)){ switch(strtolower($match[2])){ case 'g': if($match[1]>1){ $this->trigger_error('Max cache size 1G',E_USER_ERROR); } $size = $match[1]<<30; break; case 'm': $size = $match[1]<<20; break; case 'k': $size = $match[1]<<10; break; default: $size = $match[1]; } if($size<=0){ $this->trigger_error('Error cache size '.$this->max_size,E_USER_ERROR); return false; }elseif($size<10485760){ return 10485760; }else{ return $size; } }else{ return $default; } } function _format($truncate=false){ if($this->lock(true,true)){ if($truncate){ $this->_seek(0); ftruncate($this->_rs,$this->idx_node_base); } $this->max_size = $this->_parse_str_size(SECACHE_SIZE,15728640); //default:15m $this->_puts($this->header_padding,pack('V1a*',$this->max_size,$this->ver)); ksort($this->_bsize_list); $ds_offset = $this->data_base_pos; $i=0; foreach($this->_bsize_list as $size=>$count){ //将预分配的空间注册到free链表里 $count *= min(3,floor($this->max_size/10485760)); $next_free_node = 0; for($j=0;$j<$count;$j++){ $this->_puts($ds_offset,pack('V',$next_free_node)); $next_free_node = $ds_offset; $ds_offset+=intval($size); } $code = pack(str_repeat('V1',count($this->schema_struct)),$size,$next_free_node,0,0,0,0); $this->_puts(60+$i*$this->schema_item_size,$code); $i++; } $this->_set_dcur_pos($ds_offset); $this->_puts($this->idx_base_pos,str_repeat("\0",262144)); $this->_puts($this->idx_seq_pos,pack('V',1)); $this->unlock(); return true; }else{ $this->trigger_error("Couldn't lock the file !",E_USER_ERROR); return false; } } function _get_node_root($key){ $this->_seek(hexdec(substr($key,0,4))*4+$this->idx_base_pos); $a= fread($this->_rs,4); list(,$offset) = unpack('V',$a); return $offset; } function _set_node_root($key,$value){ return $this->_puts(hexdec(substr($key,0,4))*4+$this->idx_base_pos,pack('V',$value)); } function _set_node($pos,$key,$value){ if(!$pos){ return false; } if(isset($this->_node_struct[$key])){ return $this->_puts($pos*$this->idx_node_size+$this->idx_node_base+$this->_node_struct[$key][0],pack($this->_node_struct[$key][1],$value)); }else{ return false; } } function _get_pos_by_key($offset,$key,&$pos){ if(!$offset){ $pos = 0; return false; } $info = $this->_get_node($offset); if($info['key']==$key){ $pos = $info['offset']; return true; }elseif($info['next'] && $info['next']!=$offset){ return $this->_get_pos_by_key($info['next'],$key,$pos); }else{ $pos = $offset; return false; } } function _lru_delete($info){ if($info['lru_right']){ $this->_set_node($info['lru_right'],'lru_left',$info['lru_left']); }else{ $this->_set_schema($this->_get_size_schema_id($info['size']),'lru_tail',$info['lru_left']); } if($info['lru_left']){ $this->_set_node($info['lru_left'],'lru_right',$info['lru_right']); }else{ $this->_set_schema($this->_get_size_schema_id($info['size']),'lru_head',$info['lru_right']); } return true; } function _lru_push($schema_id,$offset){ $lru_head = $this->_get_schema($schema_id,'lru_head'); $lru_tail = $this->_get_schema($schema_id,'lru_tail'); if((!$offset) || ($lru_head==$offset))return; $info = $this->_get_node($offset); $this->_set_node($info['lru_right'],'lru_left',$info['lru_left']); $this->_set_node($info['lru_left'],'lru_right',$info['lru_right']); $this->_set_node($offset,'lru_right',$lru_head); $this->_set_node($offset,'lru_left',0); $this->_set_node($lru_head,'lru_left',$offset); $this->_set_schema($schema_id,'lru_head',$offset); if($lru_tail==0){ $this->_set_schema($schema_id,'lru_tail',$offset); }elseif($lru_tail==$offset && $info['lru_left']){ $this->_set_schema($schema_id,'lru_tail',$info['lru_left']); } return true; } function _get_node($offset){ $this->_seek($offset*$this->idx_node_size + $this->idx_node_base); $info = unpack('V1next/V1prev/V1data/V1size/V1lru_right/V1lru_left/H*key',fread($this->_rs,$this->idx_node_size)); $info['offset'] = $offset; return $info; } function _lru_pop($schema_id){ if($node = $this->_get_schema($schema_id,'lru_tail')){ $info = $this->_get_node($node); if(!$info['data']){ return false; } $this->delete($info['key'],$info['offset']); if(!$this->_get_schema($schema_id,'free')){ $this->trigger_error('pop lru,But nothing free...',E_USER_ERROR); } return $info; }else{ return false; } } function _dalloc($schema_id,$lru_freed=false){ if($free = $this->_get_schema($schema_id,'free')){ //如果lru里有链表 $this->_seek($free); list(,$next) = unpack('V',fread($this->_rs,4)); $this->_set_schema($schema_id,'free',$next); return $free; }elseif($lru_freed){ $this->trigger_error('Bat lru poped freesize',E_USER_ERROR); return false; }else{ $ds_offset = $this->_get_dcur_pos(); $size = $this->_get_schema($schema_id,'size'); if($size+$ds_offset > $this->max_size){ if($info = $this->_lru_pop($schema_id)){ return $this->_dalloc($schema_id,$info); }else{ $this->trigger_error('Can\'t alloc dataspace',E_USER_ERROR); return false; } }else{ $this->_set_dcur_pos($ds_offset+$size); return $ds_offset; } } } function _get_dcur_pos(){ $this->_seek($this->dfile_cur_pos); list(,$ds_offset) = unpack('V',fread($this->_rs,4)); return $ds_offset; } function _set_dcur_pos($pos){ return $this->_puts($this->dfile_cur_pos,pack('V',$pos)); } function _free_dspace($size,$pos){ if($pos>$this->max_size){ $this->trigger_error('free dspace over quota:'.$pos,E_USER_ERROR); return false; } $schema_id = $this->_get_size_schema_id($size); if($free = $this->_get_schema($schema_id,'free')){ $this->_puts($free,pack('V1',$pos)); }else{ $this->_set_schema($schema_id,'free',$pos); } $this->_puts($pos,pack('V1',0)); } function _dfollow($pos,&$c){ $c++; $this->_seek($pos); list(,$next) = unpack('V1',fread($this->_rs,4)); if($next){ return $this->_dfollow($next,$c); }else{ return $pos; } } function _free_node($pos){ $this->_seek($this->idx_free_pos); list(,$prev_free_node) = unpack('V',fread($this->_rs,4)); $this->_puts($pos*$this->idx_node_size+$this->idx_node_base,pack('V',$prev_free_node).str_repeat("\0",$this->idx_node_size-4)); return $this->_puts($this->idx_free_pos,pack('V',$pos)); } function _alloc_idx($data){ $this->_seek($this->idx_free_pos); list(,$list_pos) = unpack('V',fread($this->_rs,4)); if($list_pos){ $this->_seek($list_pos*$this->idx_node_size+$this->idx_node_base); list(,$prev_free_node) = unpack('V',fread($this->_rs,4)); $this->_puts($this->idx_free_pos,pack('V',$prev_free_node)); }else{ $this->_seek($this->idx_seq_pos); list(,$list_pos) = unpack('V',fread($this->_rs,4)); $this->_puts($this->idx_seq_pos,pack('V',$list_pos+1)); } return $this->_create_node($list_pos,$data); } function _create_node($pos,$data){ $this->_puts($pos*$this->idx_node_size + $this->idx_node_base ,pack('V1V1V1V1V1V1H*',$data['next'],$data['prev'],$data['data'],$data['size'],$data['lru_right'],$data['lru_left'],$data['key'])); return $pos; } function _set_schema($schema_id,$key,$value){ $info = array_flip($this->schema_struct); return $this->_puts(60+$schema_id*$this->schema_item_size + $info[$key]*4,pack('V',$value)); } function _get_schema($id,$key){ $info = array_flip($this->schema_struct); $this->_seek(60+$id*$this->schema_item_size); unpack('V1'.implode('/V1',$this->schema_struct),fread($this->_rs,$this->schema_item_size)); $this->_seek(60+$id*$this->schema_item_size + $info[$key]*4); list(,$value) =unpack('V',fread($this->_rs,4)); return $value; } function _all_schemas(){ $schema = array(); for($i=0;$i<16;$i++){ $this->_seek(60+$i*$this->schema_item_size); $info = unpack('V1'.implode('/V1',$this->schema_struct),fread($this->_rs,$this->schema_item_size)); if($info['size']){ $info['id'] = $i; $schema[$i] = $info; }else{ return $schema; } } } function schemaStatus(){ $return = array(); foreach($this->_all_schemas() as $k=>$schemaItem){ if($schemaItem['free']){ $this->_dfollow($schemaItem['free'],$schemaItem['freecount']); } $return[] = $schemaItem; } return $return; } function status(&$curBytes,&$totalBytes){ $totalBytes = $curBytes = 0; $hits = $miss = 0; $schemaStatus = $this->schemaStatus(); $totalBytes = $this->max_size; $freeBytes = $this->max_size - $this->_get_dcur_pos(); foreach($schemaStatus as $schema){ $freeBytes+=$schema['freecount']*$schema['size']; $miss += $schema['miss']; $hits += $schema['hits']; } $curBytes = $totalBytes-$freeBytes; $return[] = array('name'=>'缓存命中','value'=>$hits); $return[] = array('name'=>'缓存未命中','value'=>$miss); return $return; } function trigger_error($errstr,$errno){ trigger_error($errstr,$errno); } } ?> ================================================ FILE: lib/cache.php ================================================ get($key); if(!is_null($value)){ return $value; }elseif(is_callable($default)){ $value = $default(); self::set($key, $value, $expire); return $value; }elseif(!is_null($default)){ self::set($key, $default, $expire); return $default; } } // 设置缓存 static function set($key, $value, $expire=99999999){ return self::c()->set($key, $value, $expire); } // 清空缓存 static function clear(){ return self::c()->clear(); } // 删除缓存 static function del($key){ return self::set($key, null); } // 判断缓存是否设置 static function has($key){ if(is_null(self::get($key))){ return false; }else{ return true; } } // 读取并删除缓存 static function pull($key){ $value = self::get($key); self::del($key); return $value; } } ================================================ FILE: lib/fetch.php ================================================ 1, //true, $head 有请求的返回值 CURLOPT_BINARYTRANSFER => true, //返回原生的Raw输出 CURLOPT_HEADER => true, //启用时会将头文件的信息作为数据流输出。 CURLOPT_FAILONERROR => true, //显示HTTP状态码,默认行为是忽略编号小于等于400的HTTP信息。 CURLOPT_AUTOREFERER => true, //当根据Location:重定向时,自动设置header中的Referer:信息。 CURLOPT_FOLLOWLOCATION => false, //跳转 CURLOPT_CONNECTTIMEOUT => 3, //在发起连接前等待的时间,如果设置为0,则无限等待。 CURLOPT_TIMEOUT => 5, //设置cURL允许执行的最长秒数。 CURLOPT_ENCODING => 'gzip,deflate', CURLOPT_SSL_VERIFYHOST => false, CURLOPT_SSL_VERIFYPEER => false, ); foreach ($opt as $k => $v) { self::$curl_opt[$k] = $v; } } /** * fetch::get('http://www.google.com/'); * fetch::post('http://www.google.com/', array('name'=>'foo')); */ public static function __callstatic($method, $args) { if (is_null(self::$curl_opt)) { self::init(); } @list($request, $post_data, $callback) = $args; if (is_callable($post_data)) { $callback = $post_data; $post_data = null; } //single_curl if (is_string($request) || !empty($request['url'])) { $request = self::bulid_request($request, $method, $post_data, $callback); return self::single_curl($request); } elseif (is_array($request)) { //rolling_curl foreach ($request as $k => $r) { $requests[$k] = self::bulid_request($r, $method, $post_data, $callback); } return self::rolling_curl($requests); } } private static function bulid_request($request, $method = 'GET', $post_data = null, $callback = null) { //url if (is_string($request)) { $request = array('url' => $request); } empty($request['method']) && $request['method'] = $method; empty($request['post_data']) && $request['post_data'] = $post_data; empty($request['callback']) && $request['callback'] = $callback; return $request; } private static function bulid_ch(&$request) { // url $ch = curl_init($request['url']); // curl_opt $curl_opt = empty($request['curl_opt']) ? array() : $request['curl_opt']; $curl_opt = $curl_opt + (array) self::$curl_opt; // method $curl_opt[CURLOPT_CUSTOMREQUEST] = strtoupper($request['method']); // post_data if (!empty($request['post_data'])) { $curl_opt[CURLOPT_POST] = true; $curl_opt[CURLOPT_POSTFIELDS] = $request['post_data']; } // header $headers = @self::bulid_request_header($request['headers'], $cookies); $curl_opt[CURLOPT_HTTPHEADER] = $headers; // cookies $request['cookies'] = empty($request['cookies']) ? fetch::$cookies : $request['cookies']; $cookies = empty($request['cookies']) ? $cookies : self::cookies_arr2str($request['cookies']); if (!empty($cookies)) { $curl_opt[CURLOPT_COOKIE] = $cookies; } //proxy $proxy = empty($request['proxy']) ? self::$proxy : $request['proxy']; if (!empty($proxy)) { $curl_opt[CURLOPT_PROXY] = $proxy; } //setopt curl_setopt_array($ch, $curl_opt); $request['curl_opt'] = $curl_opt; $request['ch'] = $ch; return $ch; } private static function response($raw, $ch) { $response = (object) curl_getinfo($ch); $response->raw = $raw; //$raw = fetch::iconv($raw, $response->content_type); $response->headers = substr($raw, 0, $response->header_size); $response->cookies = fetch::get_respone_cookies($response->headers); fetch::$cookies = array_merge((array) fetch::$cookies, $response->cookies); $response->content = substr($raw, $response->header_size); return $response; } private static function single_curl($request) { $ch = self::bulid_ch($request); $raw = curl_exec($ch); $response = self::response($raw, $ch); curl_close($ch); if (is_callable($request['callback'])) { call_user_func($request['callback'], $response, $request); } return $response; } private static function rolling_curl($requests) { $master = curl_multi_init(); $map = array(); // start the first batch of requests do { $k = key($requests); $request = current($requests); next($requests); $ch = self::bulid_ch($request); curl_multi_add_handle($master, $ch); $key = (string) $ch; $map[$key] = array($k, $request['callback']); } while (count($map) < self::$max_connect && count($map) < count($requests)); do { while (($execrun = curl_multi_exec($master, $running)) == CURLM_CALL_MULTI_PERFORM); if ($execrun != CURLM_OK) { break; } // a request was just completed -- find out which one while ($done = curl_multi_info_read($master)) { $key = (string) $done['handle']; list($k, $callback) = $map[$key]; // get the info and content returned on the request $raw = curl_multi_getcontent($done['handle']); $response = self::response($raw, $done['handle']); $responses[$k] = $response; // send the return values to the callback function. if (is_callable($callback)) { $key = (string) $done['handle']; unset($map[$key]); call_user_func($callback, $response, $requests[$k], $k); } // start a new request (it's important to do this before removing the old one) $k = key($requests); if (!empty($k)) { $k = key($requests); $request = current($requests); next($requests); $ch = self::bulid_ch($request); curl_multi_add_handle($master, $ch); $key = (string) $ch; $map[$key] = array($k, $request['callback']); curl_multi_exec($master, $running); } // remove the curl handle that just completed curl_multi_remove_handle($master, $done['handle']); } // Block for data in / output; error handling is done by curl_multi_exec if ($running) { curl_multi_select($master, 10); } } while ($running); return $responses; } private static function bulid_request_header($headers, &$cookies) { if (is_array($headers)) { $headers = join(PHP_EOL, $headers); } if (is_array(self::$headers)) { self::$headers = join(PHP_EOL, self::$headers); } $headers = self::$headers.PHP_EOL .$headers; foreach (explode(PHP_EOL, $headers) as $k => $v) { @list($k, $v) = explode(':', $v, 2); if (empty($k) || empty($v)) { continue; } $k = implode('-', array_map('ucfirst', explode('-', $k))); $tmp[$k] = $v; } foreach ((array) $tmp as $k => $v) { if ($k == 'Cookie') { $cookies = $v; } else { $return[] = $k . ':' . $v; } } return (array) $return; } public static function iconv(&$raw, $content_type) { @list($tmp, $charset) = explode('CHARSET=', strtoupper($content_type)); if (empty($charset) && stripos($content_type, 'html') > 0) { preg_match('@\ $v) { $str .= $k . "=" . $v . "; "; } return $str; } } ================================================ FILE: lib/onedrive.php ================================================ content, true); return $data; } //使用 $refresh_token,获取 $access_token static function get_token($refresh_token){ $client_id = self::$client_id; $client_secret = self::$client_secret; $redirect_uri = self::$redirect_uri; $request['url'] = self::$oauth_url."/token"; $request['post_data'] = "client_id={$client_id}&redirect_uri={$redirect_uri}&client_secret={$client_secret}&refresh_token={$refresh_token}&grant_type=refresh_token"; $request['headers']= "Content-Type: application/x-www-form-urlencoded"; $resp = fetch::post($request); $data = json_decode($resp->content, true); return $data; } //获取 $access_token, 带缓存 static function access_token(){ $token = config('@token'); if($token['expires_on'] > time()+600){ return $token['access_token']; }else{ if (empty($token) || empty($token['refresh_token'])) { $refresh_token = config('refresh_token'); } else { $refresh_token = $token['refresh_token']; } $token = self::get_token($refresh_token); if(!empty($token['refresh_token'])){ $token['expires_on'] = time()+ $token['expires_in']; config('@token', $token); return $token['access_token']; } } return ""; } // 生成一个request,带token static function request($path="/", $query=""){ $path = self::urlencode($path); $path = empty($path)?'/':":/{$path}:/"; $token = self::access_token(); $request['headers'] = "Authorization: bearer {$token}".PHP_EOL."Content-Type: application/json".PHP_EOL; $request['url'] = self::$api_url."/me/drive/root".$path.$query; return $request; } //返回目录信息 static function dir($path="/"){ $request = self::request($path, 'children?select=name,size,folder,lastModifiedDateTime,id,@microsoft.graph.downloadUrl'); $items = array(); self::dir_next_page($request, $items); //不在列表显示的文件夹 $hide_list = explode(PHP_EOL,config('onedrive_hide')); if(is_array($hide_list) && count($hide_list)>0){ foreach($hide_list as $hide_dir){ foreach($items as $key=>$_array){ $buf = trim($hide_dir); if($buf && stristr($key, $buf))unset($items[$key]); } } } return $items; } //通过分页获取页面所有item static function dir_next_page($request, &$items, $retry=0){ $resp = fetch::get($request); $data = json_decode($resp->content, true); if(empty($data) && $retry < 3){ $retry += 1; return self::dir_next_page($request, $items, $retry); } foreach((array)$data['value'] as $item){ //var_dump($item); $items[$item['name']] = array( 'name'=>$item['name'], 'id' => $item['id'], 'size'=>$item['size'], 'lastModifiedDateTime'=>strtotime($item['lastModifiedDateTime']), 'downloadUrl'=>$item['@microsoft.graph.downloadUrl'], 'folder'=>empty($item['folder'])?false:true ); } if(!empty($data['@odata.nextLink'])){ $request = self::request(); $request['url'] = $data['@odata.nextLink']; return self::dir_next_page($request, $items); } } //关键字搜索 static function search($keyword){ $token = self::access_token(); $keyword=self::urlencode($keyword); $request['headers'] = "Authorization: bearer {$token}".PHP_EOL."Content-Type: application/json".PHP_EOL; $request['url'] = self::$api_url."/me/drive/root/search(q='".$keyword."')"; $resp=fetch::get($request); $data = json_decode($resp->content, true); foreach((array)$data['value'] as $item){ //var_dump($item); $path = self::id2path($item['id']); $items[$item['name']] = array( 'name'=>$item['name'], 'id' => $item['id'], 'size'=>$item['size'], 'lastModifiedDateTime'=>strtotime($item['lastModifiedDateTime']), 'folder'=>empty($item['folder'])?false:true, 'path'=>$path ); } return $items; } //文件缩略图链接 static function thumbnail($path,$size='large'){ $request = self::request($path,"thumbnails/0?select={$size}"); $resp = fetch::get($request); $data = json_decode($resp->content, true); $request = self::request($path,"thumbnails/0?select={$size}"); return @$data[$size]['url']; } static function share($path){ $request = self::request($path,"createLink"); $post_data['type'] = 'view'; $post_data['scope'] = 'anonymous'; $resp = fetch::post($request, json_encode($post_data)); $data = json_decode($resp->content, true); return $data; } //文件上传函数 static function upload($path,$content){ $request = self::request($path,"content"); $request['post_data'] = $content; $resp = fetch::put($request); $data = @json_decode($resp->content, true); return $data; } //url上传 static function upload_url($path, $url){ $request = self::request(get_absolute_path(dirname($path)),"children"); $request['headers'] .= "Prefer: respond-async".PHP_EOL; $post_data['@microsoft.graph.sourceUrl'] = $url; $post_data['name'] = pathinfo($path, PATHINFO_BASENAME ); $post_data['file'] = json_decode("{}"); $request['post_data'] = json_encode($post_data); $resp = fetch::post($request); list($tmp, $location) = explode('Location:', $resp->headers); list($location, $tmp) = explode(PHP_EOL, $location); // return $resp; return trim($location); } static function create_upload_session($path){ $request = self::request($path, 'createUploadSession'); $request['post_data'] = '{"item": {"@microsoft.graph.conflictBehavior": "fail"}}'; $token = self::access_token(); $resp = fetch::post($request); $data = json_decode($resp->content, true); if($resp->http_code == 409){ return false; } return $data; } static function upload_session($url, $file, $offset, $length=10240){ $token = self::access_token(); $file_size = self::_filesize($file); $content_length = (($offset+$length)>$file_size)?($file_size-$offset):$length; $end = $offset+$content_length-1; $post_data = self::file_content($file, $offset, $length); $request['url'] = $url; $request['curl_opt']=[CURLOPT_TIMEOUT=>360]; $request['headers'] = "Authorization: bearer {$token}".PHP_EOL; $request['headers'] .= "Content-Length: {$content_length}".PHP_EOL; $request['headers'] .= "Content-Range: bytes {$offset}-{$end}/{$file_size}"; $request['post_data'] = $post_data; $resp = fetch::put($request); $data = json_decode($resp->content, true); return $data; } static function upload_session_status($url){ $token = self::access_token(); fetch::$headers = "Authorization: bearer {$token}".PHP_EOL."Content-Type: application/json".PHP_EOL; $resp = fetch::get($url); $data = json_decode($resp->content, true); return $data; } static function delete_upload_session($url){ $token = self::access_token(); fetch::$headers = "Authorization: bearer {$token}".PHP_EOL."Content-Type: application/json".PHP_EOL; $resp = fetch::delete($url); $data = json_decode($resp->content, true); return $data; } static function file_content($file, $offset, $length){ $handler = fopen($file, "rb") OR die('获取文件内容失败'); fseek($handler, $offset); return fread($handler, $length); } static function human_filesize($size, $precision = 1) { for($i = 0; ($size / 1024) > 1; $i++, $size /= 1024) {} return round($size, $precision).(['B','KB','MB','GB','TB','PB','EB','ZB','YB'][$i]); } static function urlencode($path){ foreach(explode('/', $path) as $k=>$v){ if(empty(!$v)){ $paths[] = rawurlencode($v); } } return @join('/',$paths); } static function _filesize($path){ if (!file_exists($path)) return false; $size = filesize($path); if (!($file = fopen($path, 'rb'))) return false; if ($size >= 0){//Check if it really is a small file (< 2 GB) if (fseek($file, 0, SEEK_END) === 0){//It really is a small file fclose($file); return $size; } } //Quickly jump the first 2 GB with fseek. After that fseek is not working on 32 bit php (it uses int internally) $size = PHP_INT_MAX - 1; if (fseek($file, PHP_INT_MAX - 1) !== 0){ fclose($file); return false; } $length = 1024 * 1024; while (!feof($file)){//Read the file until end $read = fread($file, $length); $size = bcadd($size, $length); } $size = bcsub($size, $length); $size = bcadd($size, strlen($read)); fclose($file); return $size; } //新建文件夹 public static function create_folder($path = '/', $name = '新建文件夹') { $path = self::urlencode($path); $path = empty($path) ? '/' : ":/{$path}:/"; $api = self::$api_url."/me/drive/root".$path.'/children'; $token = self::access_token(); $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => $api, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS => "{\n \"name\": \"".$name."\",\n \"folder\": { },\n \"@microsoft.graph.conflictBehavior\": \"rename\"\n}", CURLOPT_HTTPHEADER => array( 'Authorization: Bearer '.$token.'', 'Content-Type: application/json', ), )); $response = curl_exec($curl); curl_close($curl); return $response; } //文件重命名 public static function rename($itemid, $name) { $token = self::access_token(); $api = str_replace('root', 'items/'.$itemid, self::$api_url."/me/drive/root"); $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => $api, CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'PATCH', CURLOPT_POSTFIELDS => "{\n \"name\": \"".$name."\"\n}", CURLOPT_HTTPHEADER => array( 'Authorization: Bearer '.$token, 'Content-Type: application/json', ), )); $response = curl_exec($curl); curl_close($curl); return $response; } //文件删除 public static function delete($itemid = array()) { $access_token = self::access_token(); $apie = str_replace('root', 'items/', self::$api_url."/me/drive/root"); $apis = array(); for ($i = 0; $i < count($itemid); ++$i) { $apis[$i] = $apie.$itemid[$i]; } $result = $res = $ch = array(); $nch = 0; $mh = curl_multi_init(); foreach ($apis as $nk => $url) { $timeout = 20; $ch[$nch] = curl_init(); curl_setopt_array($ch[$nch], array( CURLOPT_URL => $url, CURLOPT_TIMEOUT => $timeout, CURLOPT_RETURNTRANSFER => true, CURLOPT_MAXREDIRS => 10, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'DELETE', CURLOPT_HTTPHEADER => array( 'Authorization: Bearer '.$access_token, 'Content-Type: application/json', ), )); curl_multi_add_handle($mh, $ch[$nch]); ++$nch; } /* wait for performing request */ do { $mrc = curl_multi_exec($mh, $running); } while (CURLM_CALL_MULTI_PERFORM == $mrc); while ($running && $mrc == CURLM_OK) { // wait for network if (curl_multi_select($mh, 0.5) > -1) { // pull in new data; do { $mrc = curl_multi_exec($mh, $running); } while (CURLM_CALL_MULTI_PERFORM == $mrc); } } if ($mrc != CURLM_OK) { error_log('CURL Data Error'); } /* get data */ $nch = 0; foreach ($apis as $moudle => $node) { if (($err = curl_error($ch[$nch])) == '') { $res[$nch] = curl_multi_getcontent($ch[$nch]); $result[$moudle] = $res[$nch]; } else { error_log('curl error'); } curl_multi_remove_handle($mh, $ch[$nch]); curl_close($ch[$nch]); ++$nch; } curl_multi_close($mh); return $result; } //文件批量移动 public static function move($itemid = array(), $newitemid) { // var_dump($itemid); $apis = array(); $api = str_replace('root', 'items/', self::$api_url."/me/drive/root"); for ($i = 0; $i < count($itemid); ++$i) { $apis[$i] = $api.$itemid[$i]; } // $result = $res = $ch = array(); $nch = 0; $mh = curl_multi_init(); foreach ($apis as $nk => $url) { $timeout = 20; $ch[$nch] = curl_init(); curl_setopt_array($ch[$nch], array( CURLOPT_URL => $url, CURLOPT_TIMEOUT => $timeout, CURLOPT_RETURNTRANSFER => true, CURLOPT_MAXREDIRS => 10, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'PATCH', CURLOPT_POSTFIELDS => "{\n \"parentReference\": {\n \"id\": \"".$newitemid."\"\n }\n \n}", CURLOPT_HTTPHEADER => array( 'Authorization: Bearer '.self::access_token(), 'Content-Type: application/json', ), )); curl_multi_add_handle($mh, $ch[$nch]); ++$nch; } /* wait for performing request */ do { $mrc = curl_multi_exec($mh, $running); } while (CURLM_CALL_MULTI_PERFORM == $mrc); while ($running && $mrc == CURLM_OK) { // wait for network if (curl_multi_select($mh, 0.5) > -1) { // pull in new data; do { $mrc = curl_multi_exec($mh, $running); } while (CURLM_CALL_MULTI_PERFORM == $mrc); } } if ($mrc != CURLM_OK) { error_log('CURL Data Error'); } /* get data */ $nch = 0; foreach ($apis as $moudle => $node) { if (($err = curl_error($ch[$nch])) == '') { $res[$nch] = curl_multi_getcontent($ch[$nch]); $result[$moudle] = $res[$nch]; } else { error_log('curl error'); } curl_multi_remove_handle($mh, $ch[$nch]); curl_close($ch[$nch]); ++$nch; } curl_multi_close($mh); return $result; } //文件批量复制 public static function copy($itemids=array(), $destitemid){ $detail = self::detail($destitemid); $dvid = $detail['parentReference']['driveId'];//其driveid与其父项dvid相同 $token = self::access_token(); $request['headers'] = "Authorization: bearer {$token}".PHP_EOL."Content-Type: application/json".PHP_EOL; foreach($itemids as $index => $itemid){ $itemdetail=self::detail($itemid); $request['url'] = self::$api_url."/me/drive/items/".$itemid.'/copy'; $request['post_data'] = '{"parentReference": {"driveId": "'.$dvid.'","id": "'.$destitemid.'"},"name": "'.$itemdetail['name'].'"}'; $resp[$index]=fetch::post($request); } return $resp; } //文件路径转itemid public static function path2id($path) { $request = self::request(urldecode($path)); $access_token = self::access_token(); $request['headers'] = "Authorization: bearer {$access_token}".PHP_EOL.'Content-Type: application/json'.PHP_EOL; $resp = fetch::get($request); $data = json_decode($resp->content, true); return $data['id']; } //itemid转文件路径,原理:移动项目到其本身所在文件夹,可以返回其路径信息 //itemid:待转item的id //parentid:待转item父项id。 public static function id2path($itemid) { $resp_json = self::detail($itemid); $totalpath=$resp_json['parentReference']['path']; $count=strpos($totalpath,"/drive/root:"); $pathwithroot=substr_replace($totalpath,"",$count,strlen('/drive/root:')); $count2 = strpos($pathwithroot,chr(config('onedrive_path'))); $path = config('root_path').'/'.substr_replace($pathwithroot,"",$count2,strlen(config('onedrive_root'))).'/'; $path = str_replace("//",'/',$path).$resp_json['name']; return $path; } //itemid获取详细信息 public static function detail($itemid){ $token = self::access_token(); $request['headers'] = "Authorization: bearer {$token}".PHP_EOL."Content-Type: application/json".PHP_EOL; $request['url'] = self::$api_url."/me/drive/items/".$itemid; $resp = fetch::get($request); $data = json_decode($resp->content, true); return $data; } } ================================================ FILE: lib/oneindex.php ================================================ 10485760){ return false; } return cache::get('content_'.$item['path'], function() use ($item){ $resp = fetch::get($item['downloadUrl']); if($resp->http_code == 200){ return $resp->content; } }, config('cache_expire_time') ); } //缩略图 static function thumb($path,$width=800,$height=800){ $path = self::get_absolute_path($path); if(empty(self::$thumb[$path])){ self::$thumb[$path] = cache::get('thumb_'.$path, function() use ($path){ $url = onedrive::thumbnail($path); list($url,$tmp) = explode('&width=', $url); return $url; }, config('cache_expire_time')); } self::$thumb[$path] .= strpos(self::$thumb[$path], '?')?'&':'?'; return self::$thumb[$path]."width={$width}&height={$height}"; } //获取下载链接 static function download_url($path){ $item = self::file($path); if(!empty($item['downloadUrl'])){ return $item['downloadUrl']; } return false; } static function web_url($path){ $path = self::get_absolute_path($path); $path = rtrim($path, '/'); if(!empty(config($path.'@weburl'))){ return config($path.'@weburl'); }else{ $share = onedrive::share($path); if(!empty($share['link']['webUrl'])){ config($path.'@weburl', $share['link']['webUrl']); return $share['link']['webUrl']; } } } static function direct_link($path){ $web_url = self::web_url($path); if(!empty($web_url)){ $arr = explode('/', $web_url); if( strpos($arr[2],'sharepoint.com') >0 ){ $k = array_pop($arr); unset($arr[3]); unset($arr[4]); return join('/', $arr).'/_layouts/15/download.aspx?share='.$k; }elseif ( strpos($arr[2],'1drv.ms') >0 ){ # code... } } } //工具函数获取绝对路径 static function get_absolute_path($path) { $path = str_replace(array('/', '\\', '//'), '/', $path); $parts = array_filter(explode('/', $path), 'strlen'); $absolutes = array(); foreach ($parts as $part) { if ('.' == $part) continue; if ('..' == $part) { array_pop($absolutes); } else { $absolutes[] = $part; } } return str_replace('//','/','/'.implode('/', $absolutes).'/'); } } ================================================ FILE: lib/route.php ================================================ '[^/]+', '#num' => '[0-9]+', '#all' => '.*', ); public static function __callstatic($method, $args) { if (self::$runed) { return; } if (empty(self::$method)) { self::init(); } $method = strtoupper($method); if ($method != self::$method && !in_array($method, ['ANY', 'ERROR', 'ON'])) { return; } $pattern = trim(array_shift($args), '\/'); $pattern = self::$root . $pattern; if (self::uri_match($pattern, self::$uri)) { if (is_string($args[0]) && strpos($args[0], '@') > 0) { list($class, $action) = explode('@', $args[0]); $object = new $class(); $args[0] = array($object, $action); } $return = call_user_func($args[0]); if (is_array($return)) { print json_encode($return); } else { print (string) $return; } self::$runed = true; } } public static function init() { if (!empty(self::$method)) {return;} self::$uri = self::get_uri(); self::$method = empty($_POST['_METHOD']) ? $_SERVER['REQUEST_METHOD'] : $_POST['_METHOD']; if (defined('CONTROLLER_PATH')) { spl_autoload_register(function ($class) { $file = CONTROLLER_PATH . $class . '.php'; if (file_exists($file)) { include $file; } }); } } public static function auto($controller_path) { self::init(); $uri = self::get_uri(); list($tmp, $controller, $action) = explode('/', $uri); $controller = empty($controller) ? 'IndexController' : ucfirst($controller) . 'Controller'; $action = empty($action) ? 'index' : $action; $file = $controller_path . $controller . '.php'; if (file_exists($file)) { include $file; if (is_callable(array($controller, $action))) { $obj = new $controller(); print (string) $obj->$action(); return; } } } public static function group($middleware, $callback){ self::init(); if (is_string($middleware) && strpos($middleware, '@') > 0) { list($class, $action) = explode('@', $middleware); $object = new $class(); $result = $object->$action(); }elseif(is_callable($middleware)){ $result = $middleware(); } if($result == true && is_callable($callback)){ return $callback(); } } public static function resource($name, $controller) { self::get('/' . $name, $controller . '@index'); self::get('/' . $name . '/add', $controller . '@add'); self::post('/' . $name, $controller . '@store'); self::get('/' . $name . '/{id:#num}', $controller . '@show'); self::get('/' . $name . '/{id:#num}/edit', $controller . '@edit'); self::post('/' . $name . '/{id:#num}', $controller . '@update'); self::get('/' . $name . '/{id:#num}/delete', $controller . '@delete'); } public static function uri_match($pattern, $uri) { $pattern = ($pattern == '/') ? '/' : rtrim($pattern, '\/'); $ps = explode('/', $pattern); $searches = array_keys(static::$patterns); $replaces = array_values(static::$patterns); foreach($ps as &$p){ $p = str_replace($searches, $replaces, $p); $p = preg_replace("`\{(\w+)\:([^\)]+)\}`", '(?P<$1>$2)', $p); } $pattern = join('/',$ps); if (preg_match("`^{$pattern}$`", $uri)) { preg_match_all("`^{$pattern}$`", $uri, $matches, PREG_PATTERN_ORDER); foreach ($matches as $key => $value) { if (!is_int($key)) { $_GET[$key] = $matches[$key][0]; } } return true; } } public static function get_uri() { $file = basename($_SERVER['PHP_SELF']); $path = dirname($_SERVER['PHP_SELF']); $req_uri = $_SERVER['REQUEST_URI']; if ($path != '/' && strpos($req_uri, $path) === 0) { $req_uri = substr($req_uri, strlen($path)); } if (strpos($req_uri, '/?/') === 0) { $req_uri = parse_url($req_uri, PHP_URL_QUERY); list($req_uri) = explode('&', $req_uri); unset($_GET[$req_uri]); } $uri = parse_url($req_uri, PHP_URL_PATH); return '/' . trim($uri, '\/'); } } ================================================ FILE: lib/sqlite.php ================================================ db = new PDO('sqlite:' . $filename); $this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->name = $name; $this->createTable(); } /** * @param string $key key * * @throws InvalidArgumentException * @return string|null */ public function get($key) { if (!is_string($key)) { throw new InvalidArgumentException('Expected string as key'); } $stmt = $this->db->prepare( 'SELECT value FROM ' . $this->name . ' WHERE key = :key;' ); $stmt->bindParam(':key', $key, PDO::PARAM_STR); $stmt->execute(); if ($row = $stmt->fetch(PDO::FETCH_OBJ)) { return $row->value; } return null; } /** * @param string $key key * @param string $value value * * @throws InvalidArgumentException */ public function set($key, $value) { if (!is_string($key)) { throw new InvalidArgumentException('Expected string as key'); } $queryString = 'REPLACE INTO ' . $this->name . ' VALUES (:key, :value);'; $stmt = $this->db->prepare($queryString); $stmt->bindParam(':key', $key, \PDO::PARAM_STR); $stmt->bindParam(':value', $value, \PDO::PARAM_STR); $stmt->execute(); } /** * @param string $key key * * @return null */ public function delete($key) { $stmt = $this->db->prepare( 'DELETE FROM ' . $this->name . ' WHERE key = :key;' ); $stmt->bindParam(':key', $key, \PDO::PARAM_STR); $stmt->execute(); } /** * Delete all values from store * * @return null */ public function deleteAll() { $stmt = $this->db->prepare('DELETE FROM ' . $this->name); $stmt->execute(); $this->data = array(); } /** * @return int */ public function count() { return (int) $this->db->query('SELECT COUNT(*) FROM ' . $this->name)->fetchColumn(); } /** * Create storage table in database if not exists * * @return null */ private function createTable() { $stmt = 'CREATE TABLE IF NOT EXISTS "' . $this->name . '"'; $stmt.= '(key TEXT PRIMARY KEY, value TEXT);'; $this->db->exec($stmt); } } ================================================ FILE: lib/view.php ================================================ '', 'data' => array()); static $_pos = null; static $_section = null; static function load($file, $set = null) { if (is_int(strripos($file, '..'))) { die("error view file name:$file"); } $file = str_replace('.', '/', $file); return new view($file, $set); } public function __construct($file, $set = null) { if (isset(self::$_pos)) { $this->_view['parent'] = self::$_pos; $this->with($this->_view['parent']->_view['data']); } $this->_view['file'] = $file; $this->with($set); } public function with($name, $value = NULL) { if (is_array($name)) { $this->_view['data'] = array_merge($this->_view['data'], $name); } elseif (is_string($name)) { $this->_view['data'][$name] = $value; } return $this; } public function __toString() { self::$_pos = $this; $this->_view['file'] = VIEW_PATH . $this->_view['file'] . '.php'; if(!file_exists($this->_view['file'])){ self::to404('404'); } extract($this->_view['data']); ob_start(); include $this->_view['file']; if (isset($this->_view['layout'])) { echo $this->_view['layout'] . ob_get_clean(); } self::$_pos = isset($this->_view['parent']) ? $this->_view['parent'] : NULL; $return_str = ob_get_clean(); return $return_str; } public function show() { echo $this; } static function layout($file) { ob_start(); $view_layout = self::load($file); self::$_pos->_view['layout'] = $view_layout; } static function section($name) { if (isset(self::$_pos->_view['section'][$name])) { echo self::$_pos->_view['section'][$name]; } elseif (isset(self::$_pos->_view['parent']->_view['section'][$name])) { echo self::$_pos->_view['parent']->_view['section'][$name]; } } static function begin($name) { self::$_section = $name; ob_start(); } static function end() { self::$_pos->_view['section'][self::$_section] = ob_get_clean(); self::$_section = null; } static function direct($loction) { header("Location:$loction"); exit(); } static function abort() { header("HTTP/1.1 502 Bad Gateway"); exit(); } static function to404(){ header("HTTP/1.1 404 Not Found"); exit(); } } ================================================ FILE: one.php ================================================ $localfile, // 'remotepath' => $remotepath, // 'filesize'=>onedrive::_filesize($localfile), // 'update_time'=>0 // ); // $uploads = config('@upload'); // if(empty($uploads[$remotepath])){ // $uploads[$remotepath] = $task; // config('@upload', $uploads); // } // } // } // } //} static function upload_large_file($localfile, $remotepath){ fetch::init([CURLOPT_TIMEOUT=>200]); $upload = config('@upload'); $info = $upload[$remotepath]; if(empty($info['url'])){ print ' 创建上传会话'.PHP_EOL; $data = onedrive::create_upload_session($remotepath); if(!empty($data['uploadUrl'])){ $info['url'] = $data['uploadUrl']; $info['localfile'] = $localfile; $info['remotepath'] = $remotepath; $info['filesize'] = onedrive::_filesize($localfile); $info['offset'] = 0; $info['length'] = 327680; $info['update_time'] = time(); $upload[$remotepath] = $info; config('@upload', $upload); }elseif ( $data === false ){ print ' 文件已存在!'.PHP_EOL; return; } } if(empty($info['url'])){ print ' 获取会话失败!'.PHP_EOL; sleep(3); return self::upload_large_file($localfile, $remotepath); } print ' 上传分块'.onedrive::human_filesize($info['length']).' '; $begin_time = microtime(true); $data = onedrive::upload_session($info['url'], $info['localfile'], $info['offset'], $info['length']); if(!empty($data['nextExpectedRanges'])){ $upload_time = microtime(true) - $begin_time; $info['speed'] = $info['length']/$upload_time; print onedrive::human_filesize($info['speed']).'/s'.' '.round(($info['offset']/$info['filesize'])*100).'% '.PHP_EOL; $info['length'] = intval($info['length']/$upload_time/32768*2)*327680; $info['length'] = ($info['length']>104857600)?104857600:$info['length']; list($offset, $filesize) = explode('-',$data['nextExpectedRanges'][0]); $info['offset'] = $offset; $info['update_time'] = time(); $upload[$remotepath] = $info; config('@upload', $upload); }elseif(!empty($data['@content.downloadUrl']) || !empty($data['id'])){ unset($upload[$remotepath]); config('@upload', $upload); print ' 上传完成!'.PHP_EOL; return; }else{ print ' 失败!'.PHP_EOL; $data = onedrive::upload_session_status($info['url']); if(empty($data)|| $info['length']<100){ onedrive::delete_upload_session($info['url']); unset($upload[$remotepath]); config('@upload', $upload); }elseif(!empty($data['nextExpectedRanges'])){ list($offset, $filesize) = explode('-',$data['nextExpectedRanges'][0]); $info['offset'] = $offset; $info['length'] = $info['length']/1.5; $upload[$remotepath] = $info; config('@upload', $upload); } } return self::upload_large_file($localfile, $remotepath); } } array_shift($argv); $action = str_replace(':', '_',array_shift($argv)); if(is_callable(['one',$action])){ @call_user_func_array(['one',$action], $argv); exit(); } ?> oneindex commands : cache cache:clear clear cache cache:refresh refresh cache token token:refresh refresh token upload upload:file upload a file to onedrive upload:folder upload a folder to onedrive ================================================ FILE: statics/common/offline/css/main.css ================================================ /* * Copyright (C) 2015 Binux * * This file is part of YAAW (https://github.com/binux/yaaw). * * YAAW is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * YAAW is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You may get a copy of the GNU Lesser General Public License * from http://www.gnu.org/licenses/lgpl.txt * */ .select-box { cursor: pointer; user-select: none; -moz-user-select: none; } .btn-inline { /* fix for MAC/chrome */ display: inline !important; } .btn-inline:before, .btn-inline:after { /* fix for IE8 */ content: none !important; display: none !important; } /* header */ .main-head { position: relative; } .main-head h1 { display: inline-block; } #main-alert { position: absolute; left: 0; width: 100%; text-align: center; } #main-alert-inline { display: inline-block; text-align: left; position: relative; top: -10px; z-index: 99; } #global-info { position: absolute; bottom: 0; right: 0; } #global-version { text-align: right; } /* main-control */ #main-control { margin-top: 10px; } #select-btn { margin-right: 30px; } .select-box { display: inline-block; vertical-align: text-top; border: 1px solid #C6C6C6; border: 1px solid rgba(155, 155, 155, .57); width: 14px; height: 14px; line-height: 14px; } #do-all-btn { position: relative; margin-left: 10px; } #info-btn { margin-left: 10px; } #other-grp { } /* active-tasks */ #active-tasks { margin-top: 40px; } .empty-tasks { text-align: center; padding: 8px; } .section-header { font-size: 16px; } .section-header i { margin-right: 5px; vertical-align: baseline; } /* other-tasks */ #other-tasks { margin-top: 40px; } #waiting-tasks-table { margin-bottom: 0; } #stopped-tasks-table { border-top: 0; margin-top: 0; } /* tasks */ .tasks-table { margin: 0; margin-top: 10px; } .task.selected { background-color: #F9F9F9; } .tasks-table > li { display: block; position: relative; margin-top: -1px; border-top: 1px solid #DDD; border-bottom: 1px solid #DDD; line-height: 18px; text-align: left; vertical-align: top; } .tasks-table > li:hover { background-color: #f5f5f5; } .left-area { position: relative; padding: 8px; } .right-area { position: absolute; top: 0; right: 0; padding: 8px; } .task .task-name { cursor: pointer; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .task .task-name span { word-break: break-all; margin-left: 3px; font-size: 18px; font-weight: bold; } .task .task-name .select-box { vertical-align: -15%; } .task:hover .select-box { border-color: #666; } .task .task-info span { margin-right: 8px; } .task .task-info, .task .progress-info { margin-top: 4px; } .task .progress { margin: 1px 0; } .task .download-speed, .task .upload-speed, .task .seeders { margin-right: 8px; } #other-tasks .task-info { margin: 0; overflow: hidden; white-space: nowrap; } @media (max-height: 600px) { .modal.fade.in { position: absolute; top: 260px; } } @media (max-width: 550px) { .modal.fade.in { top: 60px; } .modal-body { max-height: none; } #main-alert { top: 25px; } #offline-cached { display: none; } #select-btn { margin-right: 10px; } #not-selected-grp { float: right; } #selected-grp { float: right; } #other-grp { clear: both; margin-top: 5px; } #active-tasks { margin-top: 20px; } #active-tasks .left-area { padding-bottom: 0; margin-right: 0; } .task .task-name { margin-right: 0; overflow: visible; white-space: normal; } #active-tasks .right-area { padding-top: 0; position: relative; width: auto; } #other-tasks .left-area { margin-right: 0; } #other-tasks .right-area { position: relative; padding-top: 0; } #other-tasks .right-area .task-info { position: absolute; top: 0; left: 0; } #other-tasks .right-area .pull-right { width: 100%; } #other-tasks .right-area .pull-right .progress { margin-left: 110px; } } @media (min-width: 551px) and (max-width: 980px) { #active-tasks .left-area { margin-right: 186px; } #active-tasks .right-area { width: 170px; } #other-tasks .left-area { margin-right: 246px; } #other-tasks .right-area { width: 230px; } #other-tasks .task-info { width: 120px; } #other-tasks .progress { width: 100px; } } @media (min-width: 980px) { #active-tasks .left-area { margin-right: 286px; } #active-tasks .right-area { width: 270px; } #other-tasks .left-area { margin-right: 416px; } #other-tasks .right-area { width: 400px; } #other-tasks .task-info { width: 190px; } #other-tasks .progress { width: 200px; } } /* task infobox */ .info-open { background-color: #F9F9F9; } .info-box { } .info-box .tab-content { height: 300px; overflow-y: auto; } .info-box .nav { margin-top: -1px; margin-bottom: 0; height: 300px; } #ib-status, #ib-options, #ib-peers { position: relative; margin: 18px 0; } #ib-files .file-list { margin-left: -25px; } #ib-files ul, #ib-options ul { margin-top: 5px; } #ib-files li { display: block; cursor: pointer; line-height: 14px; padding-bottom: 6px; vertical-align: top; border-bottom: 1px solid #FFF; } #ib-files .ib-file-title:hover { border-bottom: 1px solid #666; } #ib-file-btn, #ib-options-btn { float: right !important; margin: 0 0 5px 5px; } @media (max-width: 980px) { #ib-file-btn, #ib-options-btn { float: none !important; margin-bottom: 5px; } } .ib-file-title { margin-left: 5px; } .ib-file-size { margin-left: 20px; } #ib-options li { display: block; float: left; padding-bottom: 6px; margin-right: 100px; } #ib-options li span { display: block; text-align: right; padding-right: 1em; width: 140px; line-height: 24px; } #ib-options li > * { float: left; } #ib-peers .ip_port { display: inline-block; width: 250px; } /* task-contextmenu */ #task-contextmenu { position: fixed; z-index: 99; } /* add task modal */ #add-task-modal { overflow-x: hidden; } #add-task-modal .modal-body.hover { padding: 13px; border: 2px solid #666; } #add-task-uri { text-align: center; white-space: nowrap; padding: 10px 19px; margin: 0; overflow: hidden; } #add-task-uri div { padding-right: 118px; } #uri-input { width: 100%; } #uri-textarea { box-sizing: border-box; -moz-box-sizing: border-box; width: 100%; margin: 0; } #uri-more { font-size: 7px; text-align: center; height: 10px; margin: 0 20px 20px; line-height: 10px; color: #DDD; background-color: whiteSmoke; cursor: pointer; } #uri-more:hover { background-color: #DDD; color: #999; } #torrent-up-input { position: absolute; top: 0; left: 0; text-align: right; height: 100%; width: 100%; -moz-opacity: 0; filter: alpha(opacity: 0); opacity: 0; z-index: 2; cursor: pointer; } #torrent-up-btn { position: relative; } #add-task-alert { position: relative; top: 5px; } #add-task-option { padding: 0 50px 0 20px; } @media (max-width: 480px) { #add-task-option { padding: 0 10px 0 20px; } } #add-task-option .controls { padding-right: 10px; } #add-task-option .input-xlarge { width: 100%; } #add-task-option .half { float: left; width: 220px; } #add-task-option .control-label { width: 70px; } #add-task-option .controls { margin-left: 85px; } /* aria2 global setting */ #copyright { margin-top: 10px; float: left; } #setting-form .rpc-path-group .controls { padding-right: 70px; } @media (max-width: 480px) { #setting-form .rpc-path-group .controls { padding-right: 35px; } } #setting-form .rpc-path-wrap { padding-right: 34px; width: 100%; } #setting-form .rpc-path-wrap .add-on { position: absolute; right: 1px; } #rpc-path { width: 100%; height: 28px; box-sizing: border-box; -moz-box-sizing: border-box; } #aria2-gs-form { margin-right: 30px; } @media (max-width: 480px) { #aria2-gs-form { margin-right: 0; } } #aria2-gs-form .controls { padding-right: 10px; } #aria2-gs-form .input-xlarge { width: 100%; } #aria2-gs-form .half { float: left; width: 240px; margin-left: 10px; } #aria2-gs-form .half .control-label { width: 110px; } #aria2-gs-form .half .controls { margin-left: 130px; padding-right: 0; } /* vim: set et sw=4 ts=4 sts=4 fdm=marker ff=unix fenc=utf8: */ ================================================ FILE: statics/common/offline/js/aria2.js ================================================ /* * Copyright (C) 2015 Binux * * This file is part of YAAW (https://github.com/binux/yaaw). * * YAAW is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * YAAW is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You may get a copy of the GNU Lesser General Public License * from http://www.gnu.org/licenses/lgpl.txt * */ if (typeof ARIA2=="undefined"||!ARIA2) var ARIA2=(function(){ var jsonrpc_interface, jsonrpc_protocol, jsonrpc_ws, interval_id, rpc_secret = null, unique_id = 0, ws_callback = {}; var active_tasks_snapshot="", finished_tasks_list=undefined, tasks_cnt_snapshot="", select_lock=false, need_refresh=false; var auto_refresh=false; function get_error(result) { if (typeof result == "string") return result; else if (typeof result.error == "string") return result.error; else if (result.error && result.error.message) return result.error.message; } function default_error(result) { //console.debug(result); var error_msg = get_error(result); $("#main-alert .alert").attr("class", "alert alert-error"); $("#main-alert .alert-msg").html("Error: "+error_msg); $("#main-alert").show(); } function main_alert(_class, msg, timeout) { var msg_id = (new Date()).getTime(); $("#main-alert .alert").attr("class", "alert "+_class); $("#main-alert .alert-msg").html(msg); $("#main-alert").data("msg_id", msg_id).show(); if (timeout) { window.setTimeout(function() { if($("#main-alert").data("msg_id") == msg_id) { $("#main-alert").fadeOut(); } }, timeout); } return msg_id; } function bind_event(dom) { dom.find("[rel=tooltip]").tooltip({"placement": "bottom", trigger : 'hover'}); } function get_title(result) { var dir = result.dir; var title = "Unknown"; if (result.bittorrent && result.bittorrent.info && result.bittorrent.info.name) title = result.bittorrent.info.name; else if (result.files[0].path && result.files[0].path.replace( new RegExp("^"+dir.replace(/\\/g, "/").replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')+"/?"), "").split("/").length) { title = result.files[0].path.replace(new RegExp("^"+dir.replace(/\\/g, "/").replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')+"/?"), "").split("/"); if (result.bittorrent) title = title[0]; else title = title[title.length-1]; } else if (result.files.length && result.files[0].uris.length && result.files[0].uris[0].uri) title = result.files[0].uris[0].uri; if (result.files.length > 1) { var cnt = 0; for (var i=0; i 1) title += " ("+cnt+ " files..)" } return title; } function request_auth(url) { return url.match(/^(?:(?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?(?:\/\/)?(?:([^:@]*(?::[^:@]*)?)?@)?/)[1]; } function remove_auth(url) { return url.replace(/^((?![^:@]+:[^:@\/]*@)[^:\/?#.]+:)?(\/\/)?(?:(?:[^:@]*(?::[^:@]*)?)?@)?(.*)/, '$1$2$3'); } return { init: function(path, onready) { var connect_msg_id = main_alert("alert-info", "connecting..."); $("#add-task-option-wrap").empty().append(YAAW.tpl.add_task_option({})); $("#aria2-gsetting").empty().append(YAAW.tpl.aria2_global_setting({})); jsonrpc_interface = path || location.protocol+"//"+(location.host.split(":")[0]||"localhost")+":6800"+"/jsonrpc"; var auth_str = request_auth(jsonrpc_interface); if (auth_str && auth_str.indexOf('token:') == 0) { rpc_secret = auth_str; jsonrpc_interface = remove_auth(jsonrpc_interface); } if (jsonrpc_interface.indexOf("http") == 0) { jsonrpc_protocol = "http"; $.jsonRPC.setup({endPoint: jsonrpc_interface, namespace: 'aria2'}); ARIA2.request = ARIA2.request_http; ARIA2.batch_request = ARIA2.batch_request_http; if (onready) onready(); if ($("#main-alert").data("msg_id") == connect_msg_id) { $("#main-alert").fadeOut(); } } else if (jsonrpc_interface.indexOf("ws") == 0 && WebSocket) { jsonrpc_protocol = "ws" jsonrpc_ws = new WebSocket(jsonrpc_interface); jsonrpc_ws.onmessage = function(event) { var data = JSON.parse(event.data); //console.debug(data); if ($.isArray(data) && data.length) { var id = data[0].id; if (ws_callback[id]) { ws_callback[id].success(data); delete ws_callback[id]; } } else { if (ws_callback[data.id]) { if (data.error) ws_callback[data.id].error(data); else ws_callback[data.id].success(data); delete ws_callback[data.id]; }; }; }; jsonrpc_ws.onerror = function(event) { console.warn("error", event); main_alert("alert-error", "websocket error. you may need reflush this page to restart."); ws_callback = {}; }; jsonrpc_ws.onopen = function() { ARIA2.request = ARIA2.request_ws; ARIA2.batch_request = ARIA2.batch_request_ws; if (onready) onready(); if ($("#main-alert").data("msg_id") == connect_msg_id) { $("#main-alert").fadeOut(); } }; } else { main_alert("alert-error", "Unknown protocol"); }; }, request: function(){}, batch_request: function(){}, request_http: function(method, params, success, error) { if (error == undefined) error = default_error; if (rpc_secret) { params = params || []; if (!$.isArray(params)) params = [params]; params.unshift(rpc_secret); } $.jsonRPC.request(method, {params:params, success:success, error:error}); }, batch_request_http: function(method, params, success, error) { if (error == undefined) error = default_error; var commands = new Array(); $.each(params, function(i, n) { n = n || []; if (!$.isArray(n)) n = [n]; if (rpc_secret) { n.unshift(rpc_secret); } commands.push({method: method, params: n}); }); $.jsonRPC.batchRequest(commands, {success:success, error:error}); }, _request_data: function(method, params, id) { var dataObj = { jsonrpc: '2.0', method: 'aria2.'+method, id: id } if(typeof(params) !== 'undefined') { dataObj.params = params; } return dataObj; }, _get_unique_id: function() { ++unique_id; return unique_id; }, request_ws: function(method, params, success, error) { var id = ARIA2._get_unique_id(); ws_callback[id] = { 'success': success || function(){}, 'error': error || default_error, }; if (rpc_secret) { params = params || []; if (!$.isArray(params)) params = [params]; params.unshift(rpc_secret); } jsonrpc_ws.send(JSON.stringify(ARIA2._request_data(method, params, id))); }, batch_request_ws: function(method, params, success, error) { var data = []; var id = ARIA2._get_unique_id(); ws_callback[id] = { 'success': success || function(){}, 'error': error || default_error, }; for (var i=0,l=params.length; i"); $("#add-task-alert .alert-msg").html(error_msg); $("#add-task-alert").show(); console.warn("add task error: "+error_msg); } } ); }, add_torrent: function(torrent, options) { if (!torrent) return false; if (!options) options = {}; ARIA2.request("addTorrent", [torrent, [], options], function(result) { //console.debug(result); ARIA2.refresh(); $("#add-task-modal").modal('hide'); YAAW.add_task.clean(); }, function(result) { //console.debug(result); var error_msg = get_error(result); $("#add-task-alert .alert-msg").text(error_msg); $("#add-task-alert").show(); console.warn("add task error: "+error_msg); }); }, add_metalink: function(metalink, options) { if (!metalink) return false; if (!options) options = {}; ARIA2.request("addMetalink", [metalink, [], options], function(result) { //console.debug(result); ARIA2.refresh(); $("#add-task-modal").modal('hide'); YAAW.add_task.clean(); }, function(result) { //console.debug(result); var error_msg = get_error(result); $("#add-task-alert .alert-msg").text(error_msg); $("#add-task-alert").show(); console.warn("add task error: "+error_msg); }); }, restart_task: function(gids) { if (!$.isArray(gids)) gids = [gids]; $.each(gids, function(n, gid) { var result = $("#task-gid-"+gid).data("raw"); var uris = []; $.each(result.files, function(n, e) { if (e.uris.length) uris.push(e.uris[0].uri); }); if (result.bittorrent) { var magnet_link = "magnet:?xt=urn:btih:"+result.infoHash; if (result.bittorrent.info.name) magnet_link += "&dn="+result.bittorrent.info.name; if (result.bittorrent.announceList.length) magnet_link += "&tr="+result.bittorrent.announceList.join("&tr="); uris.push(magnet_link); } if (uris.length > 0) { ARIA2.request("getOption", [gid], function(result) { var options = result.result; ARIA2.madd_task(uris, options); }); } }); }, tell_active: function(keys) { if (select_lock) return; ARIA2.request("tellActive", keys, function(result) { //console.debug(result); if (select_lock) return; if (!result.result) { main_alert("alert-error", "Error: rpc result error.", 5000); } var snapshot = new Array(); $.each(result.result, function(i, e) { snapshot.push(e.gid); }); if (snapshot.sort().join(",") != active_tasks_snapshot) { active_tasks_snapshot = snapshot.sort().join(","); need_refresh = true; if (auto_refresh && !select_lock) ARIA2.refresh(); } result = ARIA2.status_fix(result.result); $("#active-tasks-table").empty().append(YAAW.tpl.active_task({"tasks": result})); $.each(result, function(n, e) { $("#task-gid-"+e.gid).data("raw", e); }); bind_event($("#active-tasks-table")) } ); }, check_active_list: function() { ARIA2.request("tellActive", [["gid"]], function(result) { //console.debug(result); if (!result.result) { main_alert("alert-error", "Error: rpc result error.", 5000); } var snapshot = new Array(); $.each(result.result, function(i, e) { snapshot.push(e.gid); }); if (snapshot.sort().join(",") != active_tasks_snapshot) { active_tasks_snapshot = snapshot.sort().join(","); need_refresh = true; if (auto_refresh && !select_lock) ARIA2.refresh(); } } ); }, tell_waiting: function(keys) { if (select_lock) return; var params = [0, 1000]; if (keys) params.push(keys); ARIA2.request("tellWaiting", params, function(result) { if (select_lock) return; if (!result.result) { main_alert("alert-error", "Error: rpc result error.", 5000); } result = ARIA2.status_fix(result.result); $("#waiting-tasks-table").empty().append(YAAW.tpl.other_task({"tasks": result})); $.each(result, function(n, e) { $("#task-gid-"+e.gid).data("raw", e); }); bind_event($("#waiting-tasks-table")) if ($("#other-tasks .task").length == 0) $("#waiting-tasks-table").append($("#other-task-empty").text()) } ); }, tell_stopped: function(keys) { if (select_lock) return; var params = [0, 1000]; if (keys) params.push(keys); ARIA2.request("tellStopped", params, function(result) { //console.debug(result); if (select_lock) return; if (!result.result) { main_alert("alert-error", "Error: rpc result error.", 5000); } result = ARIA2.status_fix(result.result); if (finished_tasks_list === undefined) { finished_tasks_list = new Array(); $.each(result, function(i, e) { if (e.status != "complete") return; finished_tasks_list.push(e.gid); }); } else { $.each(result, function(i, e) { if (e.status != "complete") return; if (finished_tasks_list.indexOf(e.gid) != -1) return; if (ARIA2.finish_notification) { YAAW.notification("Aria2 Task Finished", e.title); } finished_tasks_list.push(e.gid); }); } $("#stopped-tasks-table").empty().append(YAAW.tpl.other_task({"tasks": result.reverse()})); $.each(result, function(n, e) { $("#task-gid-"+e.gid).data("raw", e); }); bind_event($("#stopped-tasks-table")) if ($("#waiting-tasks-table .empty-tasks").length > 0 && $("#stopped-tasks-table .task").length > 0) { $("#waiting-tasks-table").empty(); } } ); }, status_fix: function(results) { for (var i=0; i"), 3000); } } ); }, unpause: function(gids) { if (!$.isArray(gids)) gids = [gids]; ARIA2.batch_request("unpause", gids, function(result) { //console.debug(result); var error = new Array(); $.each(result, function(i, n) { var error_msg = get_error(n); if (error_msg) error.push(error_msg); }); if (error.length == 0) { main_alert("alert-info", "Started", 1000); ARIA2.refresh(); } else { main_alert("alert-error", error.join("
"), 3000); } } ); }, remove: function(gids) { if (!$.isArray(gids)) gids = [gids]; ARIA2.batch_request("remove", gids, function(result) { //console.debug(result); var error = new Array(); $.each(result, function(i, n) { var error_msg = get_error(n); if (error_msg) error.push(error_msg); }); if (error.length == 0) { main_alert("alert-info", "Removed", 1000); ARIA2.refresh(); } else { main_alert("alert-error", error.join("
"), 3000); } } ); }, remove_result: function(gids) { if (!$.isArray(gids)) gids = [gids]; ARIA2.batch_request("removeDownloadResult", gids, function(result) { //console.debug(result); var error = new Array(); $.each(result, function(i, n) { var error_msg = get_error(n); if (error_msg) error.push(error_msg); }); if (error.length == 0) { main_alert("alert-info", "Removed", 1000); ARIA2.tell_stopped(); } else { main_alert("alert-error", error.join("
"), 3000); } } ); }, get_options: function(gid) { ARIA2.request("getOption", [gid], function(result) { //console.debug(result); $("#ib-options").empty().append(YAAW.tpl.ib_options(result.result)); if ($("#task-gid-"+gid).attr("data-status") == "active") $("#ib-options-form *[name]:not(.active-allowed)").attr("disabled", true); } ); }, change_options: function(gid, options) { ARIA2.request("changeOption", [gid, options], function(result) { //console.debug(result); main_alert("alert-info", "option updated", 1000); } ); }, get_peers: function(gid) { ARIA2.request("getPeers", [gid], function(result) { console.debug(result); $("#ib-peers").empty().append(YAAW.tpl.ib_peers(result.result)); } ); }, pause_all: function() { ARIA2.request("pauseAll", [], function(result) { //console.debug(result); ARIA2.refresh(); main_alert("alert-info", "Paused all tasks. Please wait for action such as contacting BitTorrent tracker.", 2000); } ); }, unpause_all: function() { ARIA2.request("unpauseAll", [], function(result) { //console.debug(result); ARIA2.refresh(); main_alert("alert-info", "Unpaused all tasks.", 2000); } ); }, purge_download_result: function() { ARIA2.request("purgeDownloadResult", [], function(result) { //console.debug(result); ARIA2.refresh(); main_alert("alert-info", "Removed all completed/error/removed downloads tasks.", 2000); } ); }, get_global_option: function() { ARIA2.request("getGlobalOption", [], function(result) { if (!result.result) main_alert("alert-error", "Error: rpc result error.", 5000); result = result.result; $("#aria2-gsetting").empty().append(YAAW.tpl.aria2_global_setting(result)); } ); }, init_add_task_option: function() { ARIA2.request("getGlobalOption", [], function(result) { if (!result.result) main_alert("alert-error", "Error: rpc result error.", 5000); result = result.result; result["parameterized-uri"] = (result["parameterized-uri"] == "true" ? true : false) $("#add-task-option-wrap").empty().append(YAAW.tpl.add_task_option(result)); } ); }, change_global_option: function(options) { ARIA2.request("changeGlobalOption", [options], function(result) { if (!result.result) main_alert("alert-error", "Error: rpc result error.", 5000); else main_alert("alert-success", "Saved", 2000); } ); }, global_stat: function() { ARIA2.request("getGlobalStat", [], function(result) { if (!result.result) { main_alert("alert-error", "Error: rpc result error.", 5000); } result = result.result; var _tasks_cnt_snapshot = ""+result.numActive+","+result.numWaiting+","+result.numStopped; if (_tasks_cnt_snapshot != tasks_cnt_snapshot) { tasks_cnt_snapshot = _tasks_cnt_snapshot; need_refresh = true; if (auto_refresh && !select_lock) ARIA2.refresh(); } $("#global-speed").empty().append(YAAW.tpl.global_speed(result)); var title = "↓"+YAAW.tpl.view.format_size_0()(result.downloadSpeed); if (result.uploadSpeed > 0) title += " ↑"+YAAW.tpl.view.format_size_0()(result.uploadSpeed); title += " - Yet Another Aria2 Web Frontend"; document.title = title; } ); }, get_version: function() { ARIA2.request("getVersion", [], function(result) { if (!result.result) { main_alert("alert-error", "Error: rpc result error.", 5000); } $("#global-version").text("Aria2 "+result.result.version || ""); } ); }, get_status: function(gid) { ARIA2.request("tellStatus", [gid], function(result) { if (!result.result) { main_alert("alert-error", "Error: rpc result error.", 5000); } result = result.result; result.uris = []; for (var i=0; iError: rpc result error.", 5000); } else { main_alert("alert-success", "Change Options OK!", 2000); } } ); }, /********************************************************/ refresh: function() { if (!select_lock) { need_refresh = false; ARIA2.tell_active(); ARIA2.tell_waiting(); ARIA2.tell_stopped(); } }, select_lock: function (bool) { select_lock = bool; }, auto_refresh: function(interval) { if (interval_id) window.clearInterval(interval_id); if (!(interval > 0)) { auto_refresh = false; return ; } interval_id = window.setInterval(function() { ARIA2.global_stat(); if (select_lock) { if (need_refresh) { main_alert("", "Task list have changed since last update. Click 'Refresh' button to update task list."); } } else { if (need_refresh) { ARIA2.refresh(); } else { ARIA2.tell_active(); } } }, interval); auto_refresh = true; }, finish_notification: 1, } })(); ================================================ FILE: statics/common/offline/js/jquery.Storage.js ================================================ /** * Storage plugin * Provides a simple interface for storing data such as user preferences. * Storage is useful for saving and retreiving data from the user's browser. * For newer browsers, localStorage is used. * If localStorage isn't supported, then cookies are used instead. * Retrievable data is limited to the same domain as this file. * * Usage: * This plugin extends jQuery by adding itself as a static method. * $.Storage - is the class name, which represents the user's data store, whether it's cookies or local storage. * if ($.Storage) will tell you if the plugin is loaded. * $.Storage.set("name", "value") - Stores a named value in the data store. * $.Storage.set({"name1":"value1", "name2":"value2", etc}) - Stores multiple name/value pairs in the data store. * $.Storage.get("name") - Retrieves the value of the given name from the data store. * $.Storage.remove("name") - Permanently deletes the name/value pair from the data store. * * @author Dave Schindler * * Distributed under the MIT License * * Copyright (c) 2010 Dave Schindler * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ (function($) { // Private data var isLS=typeof window.localStorage!=='undefined'; // Private functions function wls(n,v){var c;if(typeof n==="string"&&typeof v==="string"){localStorage[n]=v;return true;}else if(typeof n==="object"&&typeof v==="undefined"){for(c in n){if(n.hasOwnProperty(c)){localStorage[c]=n[c];}}return true;}return false;} function wc(n,v){var dt,e,c;dt=new Date();dt.setTime(dt.getTime()+31536000000);e="; expires="+dt.toGMTString();if(typeof n==="string"&&typeof v==="string"){document.cookie=n+"="+v+e+"; path=/";return true;}else if(typeof n==="object"&&typeof v==="undefined"){for(c in n) {if(n.hasOwnProperty(c)){document.cookie=c+"="+n[c]+e+"; path=/";}}return true;}return false;} function rls(n){return localStorage[n];} function rc(n){var nn, ca, i, c;nn=n+"=";ca=document.cookie.split(';');for(i=0;i 0 && json[0].jsonrpc !== '2.0') || (!$.isArray(json) && json.jsonrpc !== '2.0')) { throw 'Version error'; } return json; } catch (e) { return { error: 'Internal server error: ' + e, version: '2.0' } } } } } }); })(jQuery); ================================================ FILE: statics/common/offline/js/mustache.js ================================================ /*! * mustache.js - Logic-less {{mustache}} templates with JavaScript * http://github.com/janl/mustache.js */ var Mustache = (typeof module !== "undefined" && module.exports) || {}; (function (exports) { exports.name = "mustache.js"; exports.version = "0.5.0-dev"; exports.tags = ["{{", "}}"]; exports.parse = parse; exports.compile = compile; exports.render = render; exports.clearCache = clearCache; // This is here for backwards compatibility with 0.4.x. exports.to_html = function (template, view, partials, send) { var result = render(template, view, partials); if (typeof send === "function") { send(result); } else { return result; } }; var _toString = Object.prototype.toString; var _isArray = Array.isArray; var _forEach = Array.prototype.forEach; var _trim = String.prototype.trim; var isArray; if (_isArray) { isArray = _isArray; } else { isArray = function (obj) { return _toString.call(obj) === "[object Array]"; }; } var forEach; if (_forEach) { forEach = function (obj, callback, scope) { return _forEach.call(obj, callback, scope); }; } else { forEach = function (obj, callback, scope) { for (var i = 0, len = obj.length; i < len; ++i) { callback.call(scope, obj[i], i, obj); } }; } var spaceRe = /^\s*$/; function isWhitespace(string) { return spaceRe.test(string); } var trim; if (_trim) { trim = function (string) { return string == null ? "" : _trim.call(string); }; } else { var trimLeft, trimRight; if (isWhitespace("\xA0")) { trimLeft = /^\s+/; trimRight = /\s+$/; } else { // IE doesn't match non-breaking spaces with \s, thanks jQuery. trimLeft = /^[\s\xA0]+/; trimRight = /[\s\xA0]+$/; } trim = function (string) { return string == null ? "" : String(string).replace(trimLeft, "").replace(trimRight, ""); }; } var escapeMap = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''' }; function escapeHTML(string) { return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { return escapeMap[s] || s; }); } /** * Adds the `template`, `line`, and `file` properties to the given error * object and alters the message to provide more useful debugging information. */ function debug(e, template, line, file) { file = file || "