├── vendor ├── composer │ ├── installed.json │ ├── autoload_classmap.php │ ├── autoload_namespaces.php │ ├── autoload_psr4.php │ ├── autoload_static.php │ ├── LICENSE │ ├── autoload_real.php │ └── ClassLoader.php └── autoload.php ├── composer.json ├── composer.lock ├── README.md └── src └── Upload └── Upload.php /vendor/composer/installed.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /vendor/autoload.php: -------------------------------------------------------------------------------- 1 | array($baseDir . '/src/Upload'), 10 | ); 11 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aileshe/upload", 3 | "description": "file upload", 4 | "type": "library", 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Dejan", 9 | "email": "673008865@qq.com" 10 | } 11 | ], 12 | "require": { 13 | "php":">=5.3" 14 | }, 15 | "autoload": { 16 | "psr-4":{ 17 | "Dj\\":"src/Upload" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /composer.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_readme": [ 3 | "This file locks the dependencies of your project to a known state", 4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", 5 | "This file is @generated automatically" 6 | ], 7 | "content-hash": "2b7a39f3f408ed27ab08a9b6987caee5", 8 | "packages": [], 9 | "packages-dev": [], 10 | "aliases": [], 11 | "minimum-stability": "stable", 12 | "stability-flags": [], 13 | "prefer-stable": false, 14 | "prefer-lowest": false, 15 | "platform": { 16 | "php": ">=5.3" 17 | }, 18 | "platform-dev": [] 19 | } 20 | -------------------------------------------------------------------------------- /vendor/composer/autoload_static.php: -------------------------------------------------------------------------------- 1 | 11 | array ( 12 | 'Dj\\' => 3, 13 | ), 14 | ); 15 | 16 | public static $prefixDirsPsr4 = array ( 17 | 'Dj\\' => 18 | array ( 19 | 0 => __DIR__ . '/../..' . '/src/Upload', 20 | ), 21 | ); 22 | 23 | public static function getInitializer(ClassLoader $loader) 24 | { 25 | return \Closure::bind(function () use ($loader) { 26 | $loader->prefixLengthsPsr4 = ComposerStaticInitded0c41947aaf8cf6e725424ec40b9ee::$prefixLengthsPsr4; 27 | $loader->prefixDirsPsr4 = ComposerStaticInitded0c41947aaf8cf6e725424ec40b9ee::$prefixDirsPsr4; 28 | 29 | }, null, ClassLoader::class); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /vendor/composer/LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) Nils Adermann, Jordi Boggiano 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is furnished 9 | to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | THE SOFTWARE. 21 | 22 | -------------------------------------------------------------------------------- /vendor/composer/autoload_real.php: -------------------------------------------------------------------------------- 1 | = 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); 27 | if ($useStaticLoader) { 28 | require_once __DIR__ . '/autoload_static.php'; 29 | 30 | call_user_func(\Composer\Autoload\ComposerStaticInitded0c41947aaf8cf6e725424ec40b9ee::getInitializer($loader)); 31 | } else { 32 | $map = require __DIR__ . '/autoload_namespaces.php'; 33 | foreach ($map as $namespace => $path) { 34 | $loader->set($namespace, $path); 35 | } 36 | 37 | $map = require __DIR__ . '/autoload_psr4.php'; 38 | foreach ($map as $namespace => $path) { 39 | $loader->setPsr4($namespace, $path); 40 | } 41 | 42 | $classMap = require __DIR__ . '/autoload_classmap.php'; 43 | if ($classMap) { 44 | $loader->addClassMap($classMap); 45 | } 46 | } 47 | 48 | $loader->register(true); 49 | 50 | return $loader; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Upload是什么? 2 | 一个PHP文件上传组件,该组件简化了上传文件的验证使用会更简单优雅! 3 | 4 | # 安装 5 | 通过composer,这是推荐的方式,可以使用composer.json 声明依赖,或者直接运行下面的命令。 6 | ``` 7 | composer require aileshe/upload:* 8 | ``` 9 | 放入composer.json文件中 10 | ``` 11 | "require": { 12 | "aileshe/upload": "*" 13 | } 14 | ``` 15 | 然后运行 16 | ``` 17 | composer update 18 | ``` 19 | 20 | # 基本用法 21 | 以下是一个模拟 "单文件上传" 和 "多文件上传" 的Demo表单HTML代码 22 | ``` 23 | 24 |
25 | 本地单文件上传 26 |
27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 |
35 | 本地多文件上传 36 |
37 |
38 |
39 | 40 | 41 |
42 |
43 | 44 | ``` 45 | upload.php 代码如下 46 | ``` 47 | $upload = new \Dj\Upload(); 48 | $filelist = $upload->save('./upload'); 49 | if(is_array($filelist)){ 50 | # 返回数组,文件就上传成功了 51 | print_r($filelist); 52 | }else{ 53 | # 如果返回负整数(int)就是发生错误了 54 | $error_msg = [-1=>'上传失败',-2=>'文件存储路径不合法',-3=>'上传非法格式文件',-4=>'文件大小不合符规定',-5=>'token验证错误']; 55 | echo $error_msg[$filelist]; 56 | } 57 | ``` 58 | 上传成功返回打印结果 59 | ``` 60 | # 单文件上传 61 | Array 62 | ( 63 | [name] => 919ff6986614ada.jpg // 上传时的原文件名 64 | [ext] => jpg // 文件后缀名 65 | [mime] => image/jpeg // 文件MIME 66 | [size] => 171635 // 文件大小(单位:字节) 67 | [savename] => 1524626782VGdnXS50.jpg // 文件上传后在服务器上存储的名称 68 | [savepath] => E:/WWW/composer/upload_dev/upload/1524626782VGdnXS50.jpg // 上传到服务器的存储绝对路径 69 | [url] => http://upload.a.com/upload/1524626782VGdnXS50.jpg // 文件访问URL地址 70 | [uri] => /upload/1524626782VGdnXS50.jpg // 文件访问URI地址 71 | [md5] => 6308045756c126c8b823f4ade0bad77d // 文件MD5 72 | ) 73 | 74 | # 多文件上传 75 | Array 76 | ( 77 | [0] => Array 78 | ( 79 | [name] => dejan.jpg 80 | [ext] => jpg 81 | [mime] => image/jpeg 82 | [size] => 1964 83 | [savename] => 1524627074JQLQuKXs.jpg 84 | [savepath] => E:/WWW/composer/upload_dev/upload/1524627074JQLQuKXs.jpg 85 | [url] => http://upload.a.com/upload/1524627074JQLQuKXs.jpg 86 | [uri] => /upload/1524627074JQLQuKXs.jpg 87 | [md5] => 9382a7b44ea865519c82d077cd6346b0 88 | ) 89 | 90 | [1] => Array 91 | ( 92 | [name] => 《系统安装手册》.docx 93 | [ext] => docx 94 | [mime] => application/vnd.openxmlformats-officedocument.wordprocessingml.document 95 | [size] => 1041956 96 | [savename] => 1524627074oQVSkUO2.docx 97 | [savepath] => E:/WWW/composer/upload_dev/upload/1524627074oQVSkUO2.docx 98 | [url] => http://upload.a.com/upload/1524627074oQVSkUO2.docx 99 | [uri] => /upload/1524627074oQVSkUO2.docx 100 | [md5] => 9f1c186790769c09a9318eb352deb114 101 | ) 102 | 103 | [2] => Array 104 | ( 105 | [name] => 测试导入用户.xlsx 106 | [ext] => xlsx 107 | [mime] => application/vnd.openxmlformats-officedocument.spreadsheetml.sheet 108 | [size] => 9249 109 | [savename] => 1524627074LUkMlrPQ.xlsx 110 | [savepath] => E:/WWW/composer/upload_dev/upload/1524627074LUkMlrPQ.xlsx 111 | [url] => http://upload.a.com/upload/1524627074LUkMlrPQ.xlsx 112 | [uri] => /upload/1524627074LUkMlrPQ.xlsx 113 | [md5] => b1f1c10005fcf0a2b59326a3aa3af032 114 | ) 115 | 116 | ) 117 | 118 | ``` 119 | ### $upload->save($storage, $allow, $host) 120 | 121 | > \- storage [string] 122 | 123 | 上传文件到哪的存储路径 124 | 125 | > \- allow (optional) [array] 126 | 127 | 文件上传过滤允许规则定义 128 | 129 | > \- host (optional) [string] 130 | 131 | 上传到服务器后文件的URL访问域名 132 | 133 | ### $upload->save($storage, $host) 134 | 135 | > \- storage [string] 136 | 137 | 上传文件到哪的存储路径 138 | 139 | > \- host (optional) [string] 140 | 141 | 上传到服务器后文件的URL访问域名 142 | 143 | 144 | 145 | #### 返回值参照: 146 | 147 | 返回值 | 说明 148 | :--------:|:----------: 149 | Array() | 上传文件成功 150 | -1 | 上传失败 151 | -2 | 指定上传文件的存储路径不合法 152 | -3 | 上传非法格式文件 153 | -4 | 文件大小不合符规定 154 | -5 | token验证错误 155 | 156 | # 高级用法 157 | #### 1) 设置上传文件表单name, 默认是'file' 158 | ``` 159 | new \Dj\Upload('form-file-name'); # 160 | ``` 161 | 162 | #### 2) 开启 token验证 163 | ``` 164 | $upload = new \Dj\Upload(); 165 | $upload->token('FFFX123456'); # 设置 token 166 | $filelist = $upload->save('./upload'); 167 | 168 | # 或 169 | 170 | $upload = new \Dj\Upload(); 171 | $filelist = $upload->token('FFFX123456')->save('./upload'); 172 | ``` 173 | 同时在上传文件时要也要POST提交正确的token 174 | ``` 175 |
176 | 177 | 178 | 179 |
180 | ``` 181 | 182 | #### 3) 上传指定格式文件(通过后缀名方式限制) 183 | ``` 184 | $upload = new \Dj\Upload(); 185 | $filelist = $upload->save('./upload', [ 186 | 'ext'=>'jpg,jpeg,png,gif' 187 | ]); 188 | 189 | # 或 190 | 191 | $upload = new \Dj\Upload(); 192 | $filelist = $upload->save('./upload', [ 193 | 'ext'=>['jpg','jpeg','png','gif'] 194 | ]); 195 | ``` 196 | 197 | #### 4) 上传指定格式文件(通过MIME方式限制) 198 | ``` 199 | $upload = new \Dj\Upload(); 200 | $filelist = $upload->save('./upload', [ 201 | 'mime'=>'image/jpeg,image/gif,image/bmp' 202 | ]); 203 | 204 | # 或 205 | 206 | $upload = new \Dj\Upload(); 207 | $filelist = $upload->save('./upload', [ 208 | 'mime'=>['image/jpeg','image/gif','image/bmp'] 209 | ]); 210 | ``` 211 | 212 | #### 5) 上传文件许可的大小限制 213 | ``` 214 | $upload = new \Dj\Upload(); 215 | $filelist = $upload->save('./upload', [ 216 | 'size'=>5242880 217 | ]); 218 | ``` 219 | 同时"过滤参数"是可以混用的, 如 只想限制文件大小和文件类型、可以上传xx后缀的同时要匹配MIME等.. 都可以的大胆相信无所不能! 220 | ``` 221 | $upload = new \Dj\Upload(); 222 | $filelist = $upload->save('./upload', [ 223 | 'ext'=>'jpg,jpeg,png,gif', 224 | 'mime'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 225 | 'size'=>5242880 226 | ]); 227 | 228 | # 或 229 | 230 | $upload = new \Dj\Upload(); 231 | $filelist = $upload->save('./upload', [ 232 | 'ext'=>'jpg,jpeg,png,gif', 233 | 'size'=>5242880 234 | ]); 235 | 236 | # 或 237 | 238 | $upload = new \Dj\Upload(); 239 | $filelist = $upload->save('./upload', [ 240 | 'ext'=>'jpg,jpeg,png,gif', 241 | 'mime'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document' 242 | ]); 243 | ``` 244 | 245 | #### 6) 设置上传后返回文件URL的域名 246 | ``` 247 | $upload = new \Dj\Upload(); 248 | $filelist = $upload->save('./upload', 'img.sop6.com'); 249 | 250 | # 如果有过滤参数还可以这样定义 251 | 252 | $upload = new \Dj\Upload(); 253 | $filelist = $upload->save('./upload', [ 254 | 'ext'=>'jpg,jpeg,png,gif', 255 | 'mime'=>'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 256 | 'size'=>5242880 257 | ], 'img.sop6.com'); 258 | ``` 259 | 设置域名img.sop6.com后返回的上传结果如下(带 * 号那行) 260 | ``` 261 | Array 262 | ( 263 | [name] => 919ff6986614ada.jpg // 上传时的原文件名 264 | [ext] => jpg // 文件后缀名 265 | [mime] => image/jpeg // 文件MIME 266 | [size] => 171635 // 文件大小(单位:字节) 267 | [savename] => 1524626782VGdnXS50.jpg // 文件上传后在服务器上存储的名称 268 | [savepath] => E:/WWW/composer/upload_dev/upload/1524626782VGdnXS50.jpg // 上传到服务器的存储绝对路径 269 | [url] => http://img.sop6.com/upload/1524626782VGdnXS50.jpg // * 文件访问URL地址 270 | [uri] => /upload/1524626782VGdnXS50.jpg // 文件访问URI地址 271 | [md5] => 6308045756c126c8b823f4ade0bad77d // 文件MD5 272 | ) 273 | ``` 274 | 275 | # 联系方式 276 | Author: Dejan 277 | 278 | QQ: 673008865 279 | -------------------------------------------------------------------------------- /src/Upload/Upload.php: -------------------------------------------------------------------------------- 1 | frm_name = $frm_name; 23 | } 24 | 25 | /** 26 | * 设置上传口令 token 27 | * @param String $token 验证口令 28 | * @return ClassObject 29 | */ 30 | public function token($token = NULL){ 31 | $this->token = $token; 32 | return $this; 33 | } 34 | 35 | /** 36 | * 过滤允许设置 37 | * @param Array $allow 过滤允许规则 ['ext'=>'后缀名限制','size'=>193038] = ['ext'=>'png,jpg,gif','size'=>193038] 38 | * @return ClassObject 39 | */ 40 | private function allow($allow){ 41 | if($allow != NULL){ 42 | # 文件格式过滤 - 文件后缀 43 | if(isset($allow['ext']) && !empty($allow['ext'])){ 44 | if(is_array($allow['ext'])){ 45 | $this->ext = $allow['ext']; 46 | }else{ 47 | $this->ext = explode(',', $allow['ext']); 48 | } 49 | } 50 | 51 | # 文件格式过滤 - MIME 52 | if(isset($allow['mime']) && !empty($allow['mime'])){ 53 | if(is_array($allow['mime'])){ 54 | $this->mime = $allow['mime']; 55 | }else{ 56 | $this->mime = explode(',', $allow['mime']); 57 | } 58 | } 59 | 60 | # 文件大小过滤 61 | if(isset($allow['size']) && !empty($allow['size'])){ 62 | $this->size = (int)$allow['size']; 63 | } 64 | } 65 | return $this; 66 | } 67 | 68 | /** 69 | * 文件接收入口 - 单文件、多文件上传 70 | * @param String $storage 文件存储路径 71 | * @param Array $allow 允许上传文件规则 ['ext'=>'后缀名限制','size'=>193038] = ['ext'=>'png,jpg,gif','size'=>193038] 72 | * @param String $host 文件访问域名 73 | * @return Int [0上传提交空文件 -1上传失败 -2文件存储路径不合法 -5验证token为空] 74 | */ 75 | public function save($storage = NULL, $allow = NULL, $host = NULL){ 76 | # token 验证 77 | if($this->token != NULL){ 78 | if(!isset($_POST['token']) || $_POST['token'] != $this->token){ 79 | return -5; 80 | } 81 | } 82 | 83 | # 存储路径合法判断 84 | if(empty($storage) || !is_string($storage)){ 85 | return -2; 86 | } 87 | 88 | # 初始化过滤设置, 如果$allow为字符串型时自动设置 $host = $allow 89 | if(is_string($allow)){ 90 | $host = $allow; 91 | $allow = NULL; 92 | }else{ 93 | $this->allow($allow); 94 | } 95 | 96 | # 初始化文件访问域名 97 | if($host == NULL){ 98 | $this->host = 'http://'.$_SERVER['HTTP_HOST']; 99 | }else{ 100 | $this->host = preg_match('/^http[s]?\:\/\//', $host)? $host : 'http://'.$host; 101 | } 102 | 103 | if(!empty($_FILES) && isset($_FILES[$this->frm_name])){ 104 | # 判断存储目录是否存在,无则自动创建 105 | if(!is_dir($storage)){ 106 | mkdir($storage,'0777',true); 107 | chmod($storage,0777); 108 | } 109 | 110 | $save_path = realpath($storage); # 上传文件存储目录的绝对路径 111 | $filelist = array(); # 文件数组 112 | 113 | $files = $_FILES[$this->frm_name]; # 简化数组 114 | if(is_string($files['name'])){ 115 | # 单文件上传 116 | $check_res = $this->file_check($files); 117 | if($check_res === 0){ # 0 校检没问题, 118 | $filelist[] = $files; 119 | }else{ 120 | return $check_res; 121 | } 122 | }else{ 123 | # 多文件上传 124 | $file = array(); 125 | foreach($files['name'] as $k=>$v){ 126 | $file = array( 127 | 'name' => $v, 128 | 'type' => $files['type'][$k], 129 | 'tmp_name'=> $files['tmp_name'][$k], 130 | 'error' => $files['error'][$k], 131 | 'size' => $files['size'][$k] 132 | ); 133 | 134 | $check_res = $this->file_check($file); 135 | if($check_res === 0){ # 0 校检没问题 136 | $filelist[] = $file; 137 | }else{ 138 | return $check_res; 139 | } 140 | } 141 | } 142 | 143 | # 从临时空间里提取出文件到真实路径、文件信息补全 144 | $new_arr = array(); 145 | if(count($filelist) === 1){ 146 | # 单文件上传 147 | $ext = $this->get_file_ext($filelist[0]['name']); # 文件后缀名 148 | $fileName = $ext == '' ? $this->uuid() : $this->uuid().'.'.$ext; 149 | move_uploaded_file($filelist[0]['tmp_name'], $save_path.'/'.$fileName); 150 | 151 | # - 上传文件回调数据信息 152 | $new_arr['name'] = $filelist[0]['name']; # 文件上传时的原名称 153 | $new_arr['ext'] = $ext; # 文件后缀名 154 | $new_arr['mime'] = $filelist[0]['type']; # 文件MIME 155 | $new_arr['size'] = $filelist[0]['size']; # 文件大小(单位:字节) 156 | $new_arr['savename'] = $fileName; # 文件保存在服务器上名称 157 | $new_arr['savepath'] = str_replace('\\', '/', $save_path.'/'.$fileName); # 文件存储绝对路径(包含文件名) 158 | $new_arr['url'] = str_replace($_SERVER['DOCUMENT_ROOT'], $this->host, $new_arr['savepath']); # 文件访问URL地址 159 | $new_arr['uri'] = str_replace($_SERVER['DOCUMENT_ROOT'], '', $new_arr['savepath']); # 文件访问URI相对地址 160 | $new_arr['md5'] = md5_file($new_arr['savepath']); # 文件MD5 161 | }else{ 162 | # 多文件上传 163 | foreach($filelist as $v){ 164 | $ext = $this->get_file_ext($v['name']); # 文件后缀名 165 | $fileName = $ext == '' ? $this->uuid() : $this->uuid().'.'.$ext; 166 | move_uploaded_file($v['tmp_name'], $save_path.'/'.$fileName); 167 | 168 | # - 上传文件回调数据信息 169 | $savepath = str_replace('\\', '/', $save_path.'/'.$fileName); 170 | $new_arr[] = array( 171 | 'name' => $v['name'] , # 文件上传时的原名称 172 | 'ext' => $ext , # 文件后缀名 173 | 'mime' => $v['type'] , # 文件MIME 174 | 'size' => $v['size'] , # 文件大小(单位:字节) 175 | 'savename' => $fileName , # 文件保存在服务器上名称 176 | 'savepath' => $savepath , # 文件存储绝对路径(包含文件名) 177 | 'url' => str_replace($_SERVER['DOCUMENT_ROOT'], $this->host, $savepath) , # 文件访问URL地址 178 | 'uri' => str_replace($_SERVER['DOCUMENT_ROOT'], '', $savepath) , # 文件访问URI地址 179 | 'md5' => md5_file($savepath) # 文件MD5 180 | ); 181 | } 182 | } 183 | 184 | return $new_arr; 185 | }else{ 186 | return 0; # 提交上传的文件为空 187 | } 188 | } 189 | 190 | /** 191 | * 获取文件后缀名 192 | * @param String $file 文件名 193 | * @return String 194 | */ 195 | private function get_file_ext($file){ 196 | $r_offset = strrpos($file, '.'); 197 | if($r_offset){ 198 | $ext = substr($file, $r_offset + 1); 199 | }else{ 200 | $ext = ''; 201 | } 202 | 203 | return $ext; 204 | } 205 | 206 | /** 207 | * 文件唯一名称生成 208 | * @param Int $size 随机字符长度, 默认8 209 | * @return String 210 | */ 211 | private function uuid($size=8){ 212 | $chars='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; 213 | $rand_str=null; 214 | for($i=0;$i<$size;$i++){ 215 | $rand_str.=$chars[mt_rand(0,61)]; 216 | } 217 | return time().$rand_str; 218 | } 219 | 220 | /** 221 | * 文件校检 222 | * @param Array $file 单个文件数组 223 | * @return Int [0校检通过 -1上传文件失败 -3非法格式文件 -4文件大小不合符] 224 | */ 225 | private function file_check($file){ 226 | # 上传文件是否存在失败 227 | if($file['error'] !== 0){ 228 | return -1; 229 | } 230 | 231 | # 上传文件是否存在不合法的格式文件 232 | if($this->ext != NULL || $this->mime != NULL){ 233 | if(@!(in_array($this->get_file_ext($file['name']), $this->ext) || in_array($file['type'], $this->mime))){ 234 | return -3; 235 | } 236 | } 237 | 238 | # 上传文件的大小不符合规定的大小 239 | if($this->size != NULL){ 240 | if($file['size'] > $this->size){ 241 | return -4; 242 | } 243 | } 244 | 245 | return 0; 246 | } 247 | } -------------------------------------------------------------------------------- /vendor/composer/ClassLoader.php: -------------------------------------------------------------------------------- 1 | 7 | * Jordi Boggiano 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | 13 | namespace Composer\Autoload; 14 | 15 | /** 16 | * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. 17 | * 18 | * $loader = new \Composer\Autoload\ClassLoader(); 19 | * 20 | * // register classes with namespaces 21 | * $loader->add('Symfony\Component', __DIR__.'/component'); 22 | * $loader->add('Symfony', __DIR__.'/framework'); 23 | * 24 | * // activate the autoloader 25 | * $loader->register(); 26 | * 27 | * // to enable searching the include path (eg. for PEAR packages) 28 | * $loader->setUseIncludePath(true); 29 | * 30 | * In this example, if you try to use a class in the Symfony\Component 31 | * namespace or one of its children (Symfony\Component\Console for instance), 32 | * the autoloader will first look for the class under the component/ 33 | * directory, and it will then fallback to the framework/ directory if not 34 | * found before giving up. 35 | * 36 | * This class is loosely based on the Symfony UniversalClassLoader. 37 | * 38 | * @author Fabien Potencier 39 | * @author Jordi Boggiano 40 | * @see http://www.php-fig.org/psr/psr-0/ 41 | * @see http://www.php-fig.org/psr/psr-4/ 42 | */ 43 | class ClassLoader 44 | { 45 | // PSR-4 46 | private $prefixLengthsPsr4 = array(); 47 | private $prefixDirsPsr4 = array(); 48 | private $fallbackDirsPsr4 = array(); 49 | 50 | // PSR-0 51 | private $prefixesPsr0 = array(); 52 | private $fallbackDirsPsr0 = array(); 53 | 54 | private $useIncludePath = false; 55 | private $classMap = array(); 56 | private $classMapAuthoritative = false; 57 | private $missingClasses = array(); 58 | private $apcuPrefix; 59 | 60 | public function getPrefixes() 61 | { 62 | if (!empty($this->prefixesPsr0)) { 63 | return call_user_func_array('array_merge', $this->prefixesPsr0); 64 | } 65 | 66 | return array(); 67 | } 68 | 69 | public function getPrefixesPsr4() 70 | { 71 | return $this->prefixDirsPsr4; 72 | } 73 | 74 | public function getFallbackDirs() 75 | { 76 | return $this->fallbackDirsPsr0; 77 | } 78 | 79 | public function getFallbackDirsPsr4() 80 | { 81 | return $this->fallbackDirsPsr4; 82 | } 83 | 84 | public function getClassMap() 85 | { 86 | return $this->classMap; 87 | } 88 | 89 | /** 90 | * @param array $classMap Class to filename map 91 | */ 92 | public function addClassMap(array $classMap) 93 | { 94 | if ($this->classMap) { 95 | $this->classMap = array_merge($this->classMap, $classMap); 96 | } else { 97 | $this->classMap = $classMap; 98 | } 99 | } 100 | 101 | /** 102 | * Registers a set of PSR-0 directories for a given prefix, either 103 | * appending or prepending to the ones previously set for this prefix. 104 | * 105 | * @param string $prefix The prefix 106 | * @param array|string $paths The PSR-0 root directories 107 | * @param bool $prepend Whether to prepend the directories 108 | */ 109 | public function add($prefix, $paths, $prepend = false) 110 | { 111 | if (!$prefix) { 112 | if ($prepend) { 113 | $this->fallbackDirsPsr0 = array_merge( 114 | (array) $paths, 115 | $this->fallbackDirsPsr0 116 | ); 117 | } else { 118 | $this->fallbackDirsPsr0 = array_merge( 119 | $this->fallbackDirsPsr0, 120 | (array) $paths 121 | ); 122 | } 123 | 124 | return; 125 | } 126 | 127 | $first = $prefix[0]; 128 | if (!isset($this->prefixesPsr0[$first][$prefix])) { 129 | $this->prefixesPsr0[$first][$prefix] = (array) $paths; 130 | 131 | return; 132 | } 133 | if ($prepend) { 134 | $this->prefixesPsr0[$first][$prefix] = array_merge( 135 | (array) $paths, 136 | $this->prefixesPsr0[$first][$prefix] 137 | ); 138 | } else { 139 | $this->prefixesPsr0[$first][$prefix] = array_merge( 140 | $this->prefixesPsr0[$first][$prefix], 141 | (array) $paths 142 | ); 143 | } 144 | } 145 | 146 | /** 147 | * Registers a set of PSR-4 directories for a given namespace, either 148 | * appending or prepending to the ones previously set for this namespace. 149 | * 150 | * @param string $prefix The prefix/namespace, with trailing '\\' 151 | * @param array|string $paths The PSR-4 base directories 152 | * @param bool $prepend Whether to prepend the directories 153 | * 154 | * @throws \InvalidArgumentException 155 | */ 156 | public function addPsr4($prefix, $paths, $prepend = false) 157 | { 158 | if (!$prefix) { 159 | // Register directories for the root namespace. 160 | if ($prepend) { 161 | $this->fallbackDirsPsr4 = array_merge( 162 | (array) $paths, 163 | $this->fallbackDirsPsr4 164 | ); 165 | } else { 166 | $this->fallbackDirsPsr4 = array_merge( 167 | $this->fallbackDirsPsr4, 168 | (array) $paths 169 | ); 170 | } 171 | } elseif (!isset($this->prefixDirsPsr4[$prefix])) { 172 | // Register directories for a new namespace. 173 | $length = strlen($prefix); 174 | if ('\\' !== $prefix[$length - 1]) { 175 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 176 | } 177 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 178 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 179 | } elseif ($prepend) { 180 | // Prepend directories for an already registered namespace. 181 | $this->prefixDirsPsr4[$prefix] = array_merge( 182 | (array) $paths, 183 | $this->prefixDirsPsr4[$prefix] 184 | ); 185 | } else { 186 | // Append directories for an already registered namespace. 187 | $this->prefixDirsPsr4[$prefix] = array_merge( 188 | $this->prefixDirsPsr4[$prefix], 189 | (array) $paths 190 | ); 191 | } 192 | } 193 | 194 | /** 195 | * Registers a set of PSR-0 directories for a given prefix, 196 | * replacing any others previously set for this prefix. 197 | * 198 | * @param string $prefix The prefix 199 | * @param array|string $paths The PSR-0 base directories 200 | */ 201 | public function set($prefix, $paths) 202 | { 203 | if (!$prefix) { 204 | $this->fallbackDirsPsr0 = (array) $paths; 205 | } else { 206 | $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; 207 | } 208 | } 209 | 210 | /** 211 | * Registers a set of PSR-4 directories for a given namespace, 212 | * replacing any others previously set for this namespace. 213 | * 214 | * @param string $prefix The prefix/namespace, with trailing '\\' 215 | * @param array|string $paths The PSR-4 base directories 216 | * 217 | * @throws \InvalidArgumentException 218 | */ 219 | public function setPsr4($prefix, $paths) 220 | { 221 | if (!$prefix) { 222 | $this->fallbackDirsPsr4 = (array) $paths; 223 | } else { 224 | $length = strlen($prefix); 225 | if ('\\' !== $prefix[$length - 1]) { 226 | throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); 227 | } 228 | $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; 229 | $this->prefixDirsPsr4[$prefix] = (array) $paths; 230 | } 231 | } 232 | 233 | /** 234 | * Turns on searching the include path for class files. 235 | * 236 | * @param bool $useIncludePath 237 | */ 238 | public function setUseIncludePath($useIncludePath) 239 | { 240 | $this->useIncludePath = $useIncludePath; 241 | } 242 | 243 | /** 244 | * Can be used to check if the autoloader uses the include path to check 245 | * for classes. 246 | * 247 | * @return bool 248 | */ 249 | public function getUseIncludePath() 250 | { 251 | return $this->useIncludePath; 252 | } 253 | 254 | /** 255 | * Turns off searching the prefix and fallback directories for classes 256 | * that have not been registered with the class map. 257 | * 258 | * @param bool $classMapAuthoritative 259 | */ 260 | public function setClassMapAuthoritative($classMapAuthoritative) 261 | { 262 | $this->classMapAuthoritative = $classMapAuthoritative; 263 | } 264 | 265 | /** 266 | * Should class lookup fail if not found in the current class map? 267 | * 268 | * @return bool 269 | */ 270 | public function isClassMapAuthoritative() 271 | { 272 | return $this->classMapAuthoritative; 273 | } 274 | 275 | /** 276 | * APCu prefix to use to cache found/not-found classes, if the extension is enabled. 277 | * 278 | * @param string|null $apcuPrefix 279 | */ 280 | public function setApcuPrefix($apcuPrefix) 281 | { 282 | $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; 283 | } 284 | 285 | /** 286 | * The APCu prefix in use, or null if APCu caching is not enabled. 287 | * 288 | * @return string|null 289 | */ 290 | public function getApcuPrefix() 291 | { 292 | return $this->apcuPrefix; 293 | } 294 | 295 | /** 296 | * Registers this instance as an autoloader. 297 | * 298 | * @param bool $prepend Whether to prepend the autoloader or not 299 | */ 300 | public function register($prepend = false) 301 | { 302 | spl_autoload_register(array($this, 'loadClass'), true, $prepend); 303 | } 304 | 305 | /** 306 | * Unregisters this instance as an autoloader. 307 | */ 308 | public function unregister() 309 | { 310 | spl_autoload_unregister(array($this, 'loadClass')); 311 | } 312 | 313 | /** 314 | * Loads the given class or interface. 315 | * 316 | * @param string $class The name of the class 317 | * @return bool|null True if loaded, null otherwise 318 | */ 319 | public function loadClass($class) 320 | { 321 | if ($file = $this->findFile($class)) { 322 | includeFile($file); 323 | 324 | return true; 325 | } 326 | } 327 | 328 | /** 329 | * Finds the path to the file where the class is defined. 330 | * 331 | * @param string $class The name of the class 332 | * 333 | * @return string|false The path if found, false otherwise 334 | */ 335 | public function findFile($class) 336 | { 337 | // class map lookup 338 | if (isset($this->classMap[$class])) { 339 | return $this->classMap[$class]; 340 | } 341 | if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { 342 | return false; 343 | } 344 | if (null !== $this->apcuPrefix) { 345 | $file = apcu_fetch($this->apcuPrefix.$class, $hit); 346 | if ($hit) { 347 | return $file; 348 | } 349 | } 350 | 351 | $file = $this->findFileWithExtension($class, '.php'); 352 | 353 | // Search for Hack files if we are running on HHVM 354 | if (false === $file && defined('HHVM_VERSION')) { 355 | $file = $this->findFileWithExtension($class, '.hh'); 356 | } 357 | 358 | if (null !== $this->apcuPrefix) { 359 | apcu_add($this->apcuPrefix.$class, $file); 360 | } 361 | 362 | if (false === $file) { 363 | // Remember that this class does not exist. 364 | $this->missingClasses[$class] = true; 365 | } 366 | 367 | return $file; 368 | } 369 | 370 | private function findFileWithExtension($class, $ext) 371 | { 372 | // PSR-4 lookup 373 | $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; 374 | 375 | $first = $class[0]; 376 | if (isset($this->prefixLengthsPsr4[$first])) { 377 | $subPath = $class; 378 | while (false !== $lastPos = strrpos($subPath, '\\')) { 379 | $subPath = substr($subPath, 0, $lastPos); 380 | $search = $subPath.'\\'; 381 | if (isset($this->prefixDirsPsr4[$search])) { 382 | foreach ($this->prefixDirsPsr4[$search] as $dir) { 383 | $length = $this->prefixLengthsPsr4[$first][$search]; 384 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { 385 | return $file; 386 | } 387 | } 388 | } 389 | } 390 | } 391 | 392 | // PSR-4 fallback dirs 393 | foreach ($this->fallbackDirsPsr4 as $dir) { 394 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { 395 | return $file; 396 | } 397 | } 398 | 399 | // PSR-0 lookup 400 | if (false !== $pos = strrpos($class, '\\')) { 401 | // namespaced class name 402 | $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) 403 | . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); 404 | } else { 405 | // PEAR-like class name 406 | $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; 407 | } 408 | 409 | if (isset($this->prefixesPsr0[$first])) { 410 | foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { 411 | if (0 === strpos($class, $prefix)) { 412 | foreach ($dirs as $dir) { 413 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 414 | return $file; 415 | } 416 | } 417 | } 418 | } 419 | } 420 | 421 | // PSR-0 fallback dirs 422 | foreach ($this->fallbackDirsPsr0 as $dir) { 423 | if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { 424 | return $file; 425 | } 426 | } 427 | 428 | // PSR-0 include paths. 429 | if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { 430 | return $file; 431 | } 432 | 433 | return false; 434 | } 435 | } 436 | 437 | /** 438 | * Scope isolated include. 439 | * 440 | * Prevents access to $this/self from included files. 441 | */ 442 | function includeFile($file) 443 | { 444 | include $file; 445 | } 446 | --------------------------------------------------------------------------------