├── .gitignore ├── src ├── Plugins │ ├── Qetag.php │ ├── AvInfo.php │ ├── ImageInfo.php │ ├── ImageExif.php │ ├── LastReturn.php │ ├── Fetch.php │ ├── PersistentStatus.php │ ├── WithUploadToken.php │ ├── ImagePreviewUrl.php │ ├── UploadToken.php │ ├── PrivateImagePreviewUrl.php │ ├── PersistentFop.php │ ├── DownloadUrl.php │ ├── VerifyCallback.php │ └── PrivateDownloadUrl.php ├── QiniuFilesystemServiceProvider.php ├── QiniuUrl.php ├── QiniuStorage.php └── QiniuAdapter.php ├── composer.json ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.phar 2 | *.zip 3 | build/artifacts 4 | phpunit.xml 5 | phpunit.functional.xml 6 | .DS_Store 7 | .swp 8 | .build 9 | composer.lock 10 | vendor 11 | src/package.xml 12 | .idea/ 13 | -------------------------------------------------------------------------------- /src/Plugins/Qetag.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->qetag();
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class Qetag extends AbstractPlugin 21 | { 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'qetag'; 30 | } 31 | 32 | public function handle($path = null) 33 | { 34 | return $this->filesystem->getAdapter()->getLastQetag(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Plugins/AvInfo.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->avInfo('filename.mp3');
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class AvInfo extends AbstractPlugin { 21 | 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'avInfo'; 30 | } 31 | 32 | public function handle($path = null) 33 | { 34 | return $this->filesystem->getAdapter()->avInfo($path); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Plugins/ImageInfo.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->imageInfo('foo/bar1.css');
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class ImageInfo extends AbstractPlugin { 21 | 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'imageInfo'; 30 | } 31 | 32 | public function handle($path = null) 33 | { 34 | return $this->filesystem->getAdapter()->imageInfo($path); 35 | } 36 | } -------------------------------------------------------------------------------- /src/Plugins/ImageExif.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->imageExif('foo/bar1.css');
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class ImageExif extends AbstractPlugin { 21 | 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'imageExif'; 30 | } 31 | 32 | public function handle($path = null) 33 | { 34 | return $this->filesystem->getAdapter()->imageExif($path); 35 | } 36 | } -------------------------------------------------------------------------------- /src/Plugins/LastReturn.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->lastReturn();
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class LastReturn extends AbstractPlugin 21 | { 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'lastReturn'; 30 | } 31 | 32 | public function handle($path = null) 33 | { 34 | return $this->filesystem->getAdapter()->getLastReturn(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Plugins/Fetch.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->fetch('http://abc.com/foo.jpg', 'bar.jpg');
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class Fetch extends AbstractPlugin 21 | { 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'fetch'; 30 | } 31 | 32 | public function handle($url, $key) 33 | { 34 | return $this->filesystem->getAdapter()->fetch($url, $key); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Plugins/PersistentStatus.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->persistentStatus('foo/bar1.css');
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class PersistentStatus extends AbstractPlugin { 21 | 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'persistentStatus'; 30 | } 31 | 32 | public function handle($id) 33 | { 34 | return $this->filesystem->getAdapter()->persistentStatus($id); 35 | } 36 | } -------------------------------------------------------------------------------- /src/Plugins/WithUploadToken.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->withUploadToken($token);
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class WithUploadToken extends AbstractPlugin 21 | { 22 | 23 | /** 24 | * Get the method name. 25 | * 26 | * @return string 27 | */ 28 | public function getMethod() 29 | { 30 | return 'withUploadToken'; 31 | } 32 | 33 | public function handle($token) 34 | { 35 | $this->filesystem->getAdapter()->withUploadToken($token); 36 | } 37 | } -------------------------------------------------------------------------------- /src/Plugins/ImagePreviewUrl.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->imagePreviewUrl('foo/bar1.css',$ops);
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class ImagePreviewUrl extends AbstractPlugin { 21 | 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'imagePreviewUrl'; 30 | } 31 | 32 | public function handle($path = null, $ops = null) 33 | { 34 | return $this->filesystem->getAdapter()->imagePreviewUrl($path, $ops); 35 | } 36 | } -------------------------------------------------------------------------------- /src/Plugins/UploadToken.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->uploadToken('foo/bar1.css');
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class UploadToken extends AbstractPlugin { 21 | 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'uploadToken'; 30 | } 31 | 32 | public function handle($path = null, $expires = 3600, $policy = null, $strictPolicy = true) 33 | { 34 | return $this->filesystem->getAdapter()->uploadToken($path, $expires, $policy, $strictPolicy); 35 | } 36 | } -------------------------------------------------------------------------------- /src/Plugins/PrivateImagePreviewUrl.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->privateImagePreviewUrl('foo/bar1.css',$ops);
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class PrivateImagePreviewUrl extends AbstractPlugin { 21 | 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'privateImagePreviewUrl'; 30 | } 31 | 32 | public function handle($path = null, $ops = null) 33 | { 34 | return $this->filesystem->getAdapter()->privateImagePreviewUrl($path, $ops); 35 | } 36 | } -------------------------------------------------------------------------------- /src/Plugins/PersistentFop.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->persistentFop('foo/bar1.css');
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class PersistentFop extends AbstractPlugin { 21 | 22 | /** 23 | * Get the method name. 24 | * 25 | * @return string 26 | */ 27 | public function getMethod() 28 | { 29 | return 'persistentFop'; 30 | } 31 | 32 | public function handle($path = null, $fops = null, $pipline = null, $force = false, $notify_url = null) 33 | { 34 | return $this->filesystem->getAdapter()->persistentFop($path, $fops, $pipline, $force, $notify_url); 35 | } 36 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zgldh/qiniu-laravel-storage", 3 | "type": "library", 4 | "description": "Qiniu Resource (Cloud) Storage SDK for Laravel 5/6/7/8/9", 5 | "keywords": [ 6 | "qiniu", 7 | "storage", 8 | "sdk", 9 | "cloud", 10 | "laravel" 11 | ], 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "zgldh", 16 | "email": "zgldh@hotmail.com", 17 | "role": "Original Developer" 18 | }, 19 | { 20 | "name": "abcsun", 21 | "email": "chenglongsun_nj@163.com", 22 | "role": "Developer", 23 | "homepage": "http://github.com/abcsun" 24 | } 25 | ], 26 | "require": { 27 | "php": ">=5.3.3", 28 | "qiniu/php-sdk": "^7.2", 29 | "league/flysystem": "^3.0" 30 | }, 31 | "autoload": { 32 | "psr-4": { 33 | "zgldh\\QiniuStorage\\": "src/" 34 | } 35 | }, 36 | "extra": { 37 | "laravel": { 38 | "providers": [ 39 | "zgldh\\QiniuStorage\\QiniuFilesystemServiceProvider" 40 | ] 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Plugins/DownloadUrl.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->downloadUrl('foo/bar1.css');
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class DownloadUrl extends AbstractPlugin 21 | { 22 | 23 | /** 24 | * Get the method name. 25 | * 26 | * @return string 27 | */ 28 | public function getMethod() 29 | { 30 | return 'downloadUrl'; 31 | } 32 | 33 | public function handle($path = null, $domainType = 'default') 34 | { 35 | $adapter = $this->filesystem->getAdapter(); 36 | return $adapter->downloadUrl($path, $domainType); 37 | } 38 | } -------------------------------------------------------------------------------- /src/Plugins/VerifyCallback.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->verifyCallback('application/x-www-form-urlencoded', $request->header('Authorization'), 'callback url', $request->getContent());
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class VerifyCallback extends AbstractPlugin 21 | { 22 | 23 | /** 24 | * Get the method name. 25 | * 26 | * @return string 27 | */ 28 | public function getMethod() 29 | { 30 | return 'verifyCallback'; 31 | } 32 | 33 | public function handle($contentType = null, $originAuthorization = null, $url = null, $body = null) 34 | { 35 | return $this->filesystem->getAdapter()->verifyCallback($contentType, $originAuthorization, $url, $body); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Plugins/PrivateDownloadUrl.php: -------------------------------------------------------------------------------- 1 | 16 | * $disk = \Storage::disk('qiniu');
17 | * $re = $disk->getDriver()->privateDownloadUrl('foo/bar1.css');
18 | * @package zgldh\QiniuStorage\Plugins 19 | */ 20 | class PrivateDownloadUrl extends AbstractPlugin 21 | { 22 | 23 | /** 24 | * Get the method name. 25 | * 26 | * @return string 27 | */ 28 | public function getMethod() 29 | { 30 | return 'privateDownloadUrl'; 31 | } 32 | 33 | public function handle($path = null, $settings = 'default') 34 | { 35 | $adapter = $this->filesystem->getAdapter(); 36 | return $adapter->privateDownloadUrl($path, $settings); 37 | } 38 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | 21 | -------------------------------------------------------------------------------- /src/QiniuFilesystemServiceProvider.php: -------------------------------------------------------------------------------- 1 | $config['domain'], 36 | 'https' => null, 37 | 'custom' => null 38 | ]; 39 | } 40 | $qiniu_adapter = new QiniuAdapter( 41 | $config['access_key'], 42 | $config['secret_key'], 43 | $config['bucket'], 44 | $domains, 45 | isset($config['notify_url']) ? $config['notify_url'] : null, 46 | isset($config['access']) ? $config['access'] : 'public', 47 | isset($config['hotlink_prevention_key']) ? $config['hotlink_prevention_key'] : null 48 | ); 49 | $file_system = new Filesystem($qiniu_adapter); 50 | 51 | return new FilesystemAdapter($file_system, $qiniu_adapter, $config); 52 | } 53 | ); 54 | } 55 | 56 | public function register() 57 | { 58 | // 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/QiniuUrl.php: -------------------------------------------------------------------------------- 1 | url = $url; 14 | $this->hotPreventionKey = $hotPreventionKey; 15 | } 16 | 17 | public function __toString() 18 | { 19 | $url = trim($this->getUrl(), '?&'); 20 | 21 | $parameters = $this->getParameters(); 22 | 23 | if ($this->isHotlinkPrevention()) { 24 | list($sign, $t) = $this->hotlinkPreventionSign(); 25 | $parameters[] = 'sign=' . $sign; 26 | $parameters[] = 't=' . $t; 27 | } 28 | $parameterString = join('&', $parameters); 29 | 30 | if ($parameterString) { 31 | if (strrpos($url, '?') === false) { 32 | $url .= '?' . $parameterString; 33 | } else { 34 | $url .= '&' . $parameterString; 35 | } 36 | } 37 | if (is_string($url) === false) { 38 | return ''; 39 | } 40 | return $url; 41 | } 42 | 43 | /** 44 | * @return null 45 | */ 46 | public function getUrl() 47 | { 48 | return $this->url; 49 | } 50 | 51 | /** 52 | * @param null $url 53 | */ 54 | public function setUrl($url) 55 | { 56 | $this->url = $url; 57 | } 58 | 59 | /** 60 | * @return null 61 | */ 62 | public function getDownload() 63 | { 64 | return $this->getParameter('download'); 65 | } 66 | 67 | /** 68 | * @param null $download 69 | * @return QiniuUrl 70 | */ 71 | public function setDownload($download) 72 | { 73 | return $this->setParameter('download', urlencode($download)); 74 | } 75 | 76 | /** 77 | * @return array 78 | */ 79 | public function getParameter($name) 80 | { 81 | return $this->parameters[$name]; 82 | } 83 | 84 | /** 85 | * @return array 86 | */ 87 | public function getParameters() 88 | { 89 | return $this->parameters; 90 | } 91 | 92 | /** 93 | * @param $name 94 | * @param $value 95 | * @return QiniuUrl 96 | */ 97 | public function setParameter($name, $value) 98 | { 99 | $this->parameters[$name] = $name . '/' . $value; 100 | return $this; 101 | } 102 | 103 | /** 104 | * Specify data which should be serialized to JSON 105 | * @link http://php.net/manual/en/jsonserializable.jsonserialize.php 106 | * @return mixed data which can be serialized by json_encode, 107 | * which is a value of any type other than a resource. 108 | * @since 5.4.0 109 | */ 110 | function jsonSerialize() 111 | { 112 | return $this->__toString(); 113 | } 114 | 115 | private function hotlinkPreventionSign() 116 | { 117 | $t = dechex(time() + 3600); 118 | $parsedUrl = parse_url($this->url); 119 | $pendingString = $this->getHotPreventionKey() . str_replace('%2F', '/', urlencode($parsedUrl['path'])) . $t; 120 | $sign = strtolower(md5($pendingString)); 121 | return [$sign, $t]; 122 | } 123 | 124 | /** 125 | * @return bool 126 | */ 127 | public function isHotlinkPrevention() 128 | { 129 | return !!$this->getHotPreventionKey(); 130 | } 131 | 132 | /** 133 | * @return null 134 | */ 135 | public function getHotPreventionKey() 136 | { 137 | return $this->hotPreventionKey; 138 | } 139 | 140 | /** 141 | * @param null $hotPreventionKey 142 | */ 143 | public function setHotPreventionKey($hotPreventionKey) 144 | { 145 | $this->hotPreventionKey = $hotPreventionKey; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/QiniuStorage.php: -------------------------------------------------------------------------------- 1 | storage = \Storage::disk($name); 21 | } 22 | 23 | /** 24 | * 文件是否存在 25 | * @param $key 26 | * @return bool 27 | */ 28 | public function exists($key) 29 | { 30 | return $this->storage->exists($key); 31 | } 32 | 33 | /** 34 | * 获取文件内容 35 | * @param $key 36 | * @return string 37 | */ 38 | public function get($key) 39 | { 40 | return $this->storage->get($key); 41 | } 42 | 43 | /** 44 | * 上传文件 45 | * @param $key 46 | * @param $contents 47 | * @return bool 48 | */ 49 | public function put($key, $contents) 50 | { 51 | return $this->storage->put($key, $contents); 52 | } 53 | 54 | /** 55 | * 附加内容到文件开头 56 | * @param $key 57 | * @param $contents 58 | * @return int 59 | */ 60 | public function prepend($key, $contents) 61 | { 62 | return $this->storage->prepend($key, $contents); 63 | } 64 | 65 | /** 66 | * 附加内容到文件结尾 67 | * @param $key 68 | * @param $content 69 | * @return int 70 | */ 71 | public function append($key, $contents) 72 | { 73 | return $this->storage->append($key, $contents); 74 | } 75 | 76 | /** 77 | * 删除文件 78 | * @param $key 79 | * @return bool 80 | */ 81 | public function delete($key) 82 | { 83 | return $this->storage->delete($key); 84 | 85 | } 86 | 87 | /** 88 | * 复制文件到新的路径 89 | * @param $key 90 | * @param $key2 91 | * @return bool 92 | */ 93 | public function copy($key, $key2) 94 | { 95 | return $this->storage->copy($key, $key2); 96 | 97 | } 98 | 99 | /** 100 | * 移动文件到新的路径 101 | * @param $key 102 | * @param $key2 103 | * @return bool 104 | */ 105 | public function move($key, $key2) 106 | { 107 | return $this->storage->move($key, $key2); 108 | 109 | } 110 | 111 | public function size($key) 112 | { 113 | return $this->storage->size($key); 114 | 115 | } 116 | 117 | public function lastModified($key) 118 | { 119 | return $this->storage->lastModified($key); 120 | 121 | } 122 | 123 | public function files($key) 124 | { 125 | return $this->storage->files($key); 126 | } 127 | 128 | public function allFiles($key) 129 | { 130 | return $this->storage->files($key); 131 | } 132 | 133 | public function directories($key) 134 | { 135 | return $this->storage->files($key); 136 | } 137 | 138 | public function allDirectories($key) 139 | { 140 | return $this->storage->files($key); 141 | } 142 | 143 | public function makeDirectory($key) 144 | { 145 | return $this->storage->makeDirectory($key); 146 | } 147 | 148 | public function deleteDirectory($key) 149 | { 150 | return $this->storage->deleteDirectory($key); 151 | } 152 | 153 | /** 154 | * 获取上传Token 155 | * @param $key 156 | * @param $expires 157 | * @param $policy 158 | * @param $strictPolicy 159 | * @return bool 160 | */ 161 | public function uploadToken($key = null, $expires = 3600, $policy = null, $strictPolicy = true) 162 | { 163 | return $this->storage->getAdapter()->uploadToken($key, $expires, $policy, $strictPolicy); 164 | } 165 | 166 | /** 167 | * 下次 put 操作,将使用该 uploadToken 进行上传。 常用于持久化操作。 168 | * @param $token 169 | * @return mixed 170 | */ 171 | public function withUploadToken($token) 172 | { 173 | $this->storage->getAdapter()->withUploadToken($token); 174 | } 175 | 176 | /** 177 | * 获取下载地址 178 | * @param $key 179 | * @return mixed 180 | */ 181 | public function downloadUrl($key, $domainType = 'default') 182 | { 183 | return $this->storage->getAdapter()->downloadUrl($key, $domainType); 184 | } 185 | 186 | /** 187 | * 获取私有bucket下载地址 188 | * @param $key 189 | * @return mixed 190 | */ 191 | public function privateDownloadUrl($key, $domainType = 'default') 192 | { 193 | return $this->storage->getAdapter()->privateDownloadUrl($key, $domainType); 194 | } 195 | 196 | /** 197 | * 获取多媒体文件信息 198 | * @param $key 199 | * @return mixed 200 | */ 201 | public function avInfo($key) 202 | { 203 | return $this->storage->getAdapter()->avInfo($key); 204 | } 205 | 206 | /** 207 | * 获取图片信息 208 | * @param $key 209 | * @return mixed 210 | */ 211 | public function imageInfo($key) 212 | { 213 | return $this->storage->getAdapter()->imageInfo($key); 214 | } 215 | 216 | /** 217 | * 获取图片EXIF信息 218 | * @param $key 219 | * @return mixed 220 | */ 221 | public function imageExif($key) 222 | { 223 | return $this->storage->getAdapter()->imageExif($key); 224 | } 225 | 226 | /** 227 | * 获取图片预览URL 228 | * @param $key 229 | * @param $opts 230 | * @return mixed 231 | */ 232 | public function imagePreviewUrl($key, $opts) 233 | { 234 | return $this->storage->getAdapter()->imagePreviewUrl($key, $opts); 235 | } 236 | 237 | /** 238 | * 获取私有bucket图片预览URL 239 | * @param $key 240 | * @param $opts 241 | * @return mixed 242 | */ 243 | public function privateImagePreviewUrl($key, $opts) 244 | { 245 | return $this->storage->getAdapter()->privateImagePreviewUrl($key, $opts); 246 | } 247 | 248 | /** 249 | * 执行持久化数据处理 250 | * @param $key 251 | * @param $opts 252 | * @param $pipline 253 | * @param $force 254 | * @param $notify_url 255 | * @return mixed 256 | */ 257 | public function persistentFop($key, $opts, $pipline = null, $force = false, $notify_url = null) 258 | { 259 | return $this->storage->getAdapter()->persistentFop($key, $opts, $pipline, $force, $notify_url); 260 | } 261 | 262 | /** 263 | * 查看持久化数据处理的状态 264 | * @param $id 265 | * @return mixed 266 | */ 267 | public function persistentStatus($id) 268 | { 269 | return $this->storage->getAdapter()->persistentStatus($id); 270 | } 271 | 272 | /** 273 | * 验证回调是否合法 274 | * @param $id 275 | * @return boolean 276 | */ 277 | public function verifyCallback($contentType, $originAuthorization, $url, $body) 278 | { 279 | return $this->storage->getAdapter()->verifyCallback($contentType, $originAuthorization, $url, $body); 280 | } 281 | 282 | /** 283 | * 调用fetch将 foo.jpg 数据以 bar.jpg 的名字储存起来。 284 | * @param $url 285 | * @param $key 286 | * @return bool 287 | */ 288 | public function fetch($url, $key) 289 | { 290 | return $this->storage->getAdapter()->fetch($url, $key); 291 | } 292 | 293 | /** 294 | * 得到最后一次执行 put, copy, append 等写入操作后,得到的hash值。详见 https://github.com/qiniu/qetag 295 | * @return string 296 | */ 297 | public function qetag() 298 | { 299 | return $this->storage->getAdapter()->qetag(); 300 | } 301 | 302 | /** 303 | * 得到最后一次执行 put, copy, append 等写入操作后,得到的返回值。 304 | * @return array 305 | */ 306 | public function lastReturn() 307 | { 308 | return $this->storage->getAdapter()->getLastReturn(); 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qiniu 云储存 Laravel 5/6/7/8/9 Storage版 2 | 3 | 基于 https://github.com/qiniu/php-sdk 开发 4 | 5 | 符合Laravel 5/6/7/8/9 的Storage用法。 6 | 7 | ## 注意 8 | 9 |  从七牛获取到的`putTime`时间戳,是以 100纳秒 为单位的。 10 | 11 | 参考 https://developer.qiniu.com/kodo/api/1308/stat https://developer.qiniu.com/kodo/api/1284/list 12 | 13 |  PHP 可以用 [Carbon](http://carbon.nesbot.com/docs/) `Carbon::createFromTimestampMs($putTime/10000)` 来保证最大精度 14 |   15 | 16 | JavaScript 可以用 [moment](http://momentjs.cn/docs/#/parsing/unix-offset/) `moment(putTime/10000)` 来保证最大精度 17 |   18 | 19 | ## 更新 20 | 21 | v9.0 22 | 支持 Laravel 9 23 | 24 | v0.10 25 | 支持“公开空间”的 CDN 时间戳防盗链 26 | 27 | v0.9 28 | 兼容 Laravel 5.5 的自动包安装功能 29 | 30 | v0.8 31 | 1. 修正了getUrl 32 | 2. 修正了最新的 Qiniu API 适配 33 | 34 | v0.7 35 | 1. 增加了 ```withUploadToken```, ```lastReturn``` 等命令。 36 | 2. 修正了代码内的一些typo 37 | 38 | v0.6 增加了```fetch```, ```qetag``` 命令。 39 | 40 | v0.5 增加了```QiniuUrl```来更方便的设置文件 URL 参数。 41 | 42 | v0.3 增加了对PIPE以及回调地址参数的配置。 感谢abcsun提供的灵感。 43 | 44 | v0.2 提供了对多域名的支持。这是为了配合七牛的默认域名、HTTPS域名和自定义域名而添加的功能。 45 | 46 | ## 安装 47 | 48 | - ```composer require zgldh/qiniu-laravel-storage:0.10.3``` 49 | - ```config/app.php``` 里面的 ```providers``` 数组, 加上一行 ```zgldh\QiniuStorage\QiniuFilesystemServiceProvider::class``` 50 | - ```config/filesystem.php``` 里面的 ```disks```数组加上: 51 | 52 | ```php 53 | 54 | 'disks' => [ 55 | ... , 56 | 'qiniu' => [ 57 | 'driver' => 'qiniu', 58 | 'domains' => [ 59 | 'default' => 'xxxxx.com1.z0.glb.clouddn.com', //你的七牛域名 60 | 'https' => 'dn-yourdomain.qbox.me', //你的HTTPS域名 61 |                'custom'   => 'static.abc.com',               //Useless 没啥用,请直接使用上面的 default 项 62 | ], 63 | 'access_key'=> '', //AccessKey 64 | 'secret_key'=> '', //SecretKey 65 | 'bucket' => '', //Bucket名字 66 | 'notify_url'=> '', //持久化处理回调地址 67 | 'access' => 'public', //空间访问控制 public 或 private 68 | 'hotlink_prevention_key' => 'afc89ff8bd2axxxxxxxxxxxxxxbb', // CDN 时间戳防盗链的 key。 设置为 null 则不启用本功能。 69 | // 'hotlink_prevention_key' => 'cbab68a279xxxxxxxxxxab509a', // 同上,备用 70 | ], 71 | ], 72 | 73 | ``` 74 | 75 | - 完成 76 | 77 | ## 使用 78 | 79 | 第一种用法 80 | 81 | ```php 82 | 83 | $disk = \Storage::disk('qiniu'); 84 | $disk->exists('file.jpg'); //文件是否存在 85 | $disk->get('file.jpg'); //获取文件内容 86 | $disk->put('file.jpg',$contents); //上传文件 87 | $disk->put('file.jpg',fopen('path/to/big.jpg','r+')); //分段上传文件。建议大文件>10Mb使用。 88 | $disk->prepend('file.log', 'Prepended Text'); //附加内容到文件开头 89 | $disk->append('file.log', 'Appended Text'); //附加内容到文件结尾 90 | $disk->delete('file.jpg'); //删除文件 91 | $disk->delete(['file1.jpg', 'file2.jpg']); 92 | $disk->copy('old/file1.jpg', 'new/file1.jpg'); //复制文件到新的路径 93 | $disk->move('old/file1.jpg', 'new/file1.jpg'); //移动文件到新的路径 94 | $size = $disk->size('file1.jpg'); //取得文件大小 95 | $time = $disk->lastModified('file1.jpg'); //取得最近修改时间 (UNIX) 96 | $files = $disk->files($directory); //取得目录下所有文件 97 | $files = $disk->allFiles($directory); //这个没实现。。。 98 | $directories = $disk->directories($directory); //这个也没实现。。。 99 | $directories = $disk->allDirectories($directory); //这个也没实现。。。 100 | $disk->makeDirectory($directory); //这个其实没有任何作用 101 | $disk->deleteDirectory($directory); //删除目录,包括目录下所有子文件子目录 102 | $disk->url('a.png'); //返回文件的URL 103 | $disk->url(['path' => 'a.png', 'domainType' => 'default']); //返回文件的URL 104 | 105 | $disk->getAdapter()->uploadToken(); //获取上传Token 106 | $disk->getAdapter()->uploadToken('file.jpg'); //获取上传Token 107 | 108 | $disk->getAdapter()->withUploadToken($token); // 使用自定义的 uploadToken 进行上传, 109 | $disk->put('file.jpg',$content); // 则本次的 put 操作,将使用上述的 $token 进行上传。 110 | // 常用于自动触发持久化处理 https://github.com/qiniu/php-sdk/blob/master/examples/upload_and_pfop.php 111 | 112 | $disk->getAdapter()->downloadUrl('file.jpg'); //获取下载地址 113 | $disk->getAdapter()->downloadUrl('file.jpg') 114 | ->setDownload('foo.jpg'); //获取下载地址,文件名为 foo.jpg 115 | $disk->getAdapter()->downloadUrl('file.jpg', 'https'); //获取HTTPS下载地址 116 | $disk->getAdapter()->privateDownloadUrl('file.jpg'); //获取私有bucket下载地址 117 | $disk->getAdapter()->privateDownloadUrl('file.jpg?attname=foo.jpg'); 118 | //获取私有bucket下载地址,文件名为 foo.jpg 119 | $disk->getAdapter()->privateDownloadUrl('file.jpg', 'https');//获取私有bucket的HTTPS下载地址 120 | $disk->getAdapter()->privateDownloadUrl('file.jpg', 121 | [ 122 | 'domain'=>'https', 123 | 'expires'=>3600 124 | ]); //获取私有bucket的HTTPS下载地址。超时 3600 秒。 125 | $disk->getAdapter()->avInfo('file.mp3'); //获取多媒体文件信息 126 | $disk->getAdapter()->imageInfo('file.jpg'); //获取图片信息 127 | $disk->getAdapter()->imageExif('file.jpg'); //获取图片EXIF信息 128 | $disk->getAdapter()->imagePreviewUrl('file.jpg','imageView2/0/w/100/h/200'); //获取图片预览URL 129 | $disk->getAdapter()->privateImagePreviewUrl('file.jpg','imageView2/0/w/100/h/200'); //获取私有bucket图片预览URL 130 | $disk->getAdapter()->verifyCallback('application/x-www-form-urlencoded', $request->header('Authorization'), 'callback url', $request->getContent());//验证回调内容是否合法 131 | $disk->getAdapter()->persistentFop('file.flv','avthumb/m3u8/segtime/40/vcodec/libx264/s/320x240'); //执行持久化数据处理 132 | $disk->getAdapter()->persistentFop('file.flv','fop','队列名'); //使用私有队列执行持久化数据处理 133 | $disk->getAdapter()->persistentStatus($persistent_fop_id); //查看持久化数据处理的状态。 134 | $disk->getAdapter()->fetch('http://abc.com/foo.jpg', 'bar.jpg'); //调用fetch将 foo.jpg 数据以 bar.jpg 的名字储存起来。 135 | $disk->getAdapter()->qetag(); //得到最后一次执行 put, copy, append 等写入操作后,得到的hash值。详见 https://github.com/qiniu/qetag 136 | $disk->getAdapter()->lastReturn(); //得到最后一次执行 put, copy, append 等写入操作后,得到的返回值。 137 | 138 | ``` 139 | 140 | 第二种用法 (就是省略了一个getAdapter) 141 | 142 | ```php 143 | 144 | use zgldh\QiniuStorage\QiniuStorage; 145 | 146 | $disk = QiniuStorage::disk('qiniu'); 147 | $disk->exists('file.jpg'); //文件是否存在 148 | $disk->get('file.jpg'); //获取文件内容 149 | $disk->put('file.jpg',$contents); //上传文件 150 | $disk->put('file.jpg',fopen('path/to/big.jpg','r+')); //分段上传文件。建议大文件>10Mb使用。 151 | $disk->prepend('file.log', 'Prepended Text'); //附加内容到文件开头 152 | $disk->append('file.log', 'Appended Text'); //附加内容到文件结尾 153 | $disk->delete('file.jpg'); //删除文件 154 | $disk->delete(['file1.jpg', 'file2.jpg']); 155 | $disk->copy('old/file1.jpg', 'new/file1.jpg'); //复制文件到新的路径 156 | $disk->move('old/file1.jpg', 'new/file1.jpg'); //移动文件到新的路径 157 | $size = $disk->size('file1.jpg'); //取得文件大小 158 | $time = $disk->lastModified('file1.jpg'); //取得最近修改时间 (UNIX) 159 | $files = $disk->files($directory); //取得目录下所有文件 160 | $files = $disk->allFiles($directory); //这个没实现。。。 161 | $directories = $disk->directories($directory); //这个也没实现。。。 162 | $directories = $disk->allDirectories($directory); //这个也没实现。。。 163 | $disk->makeDirectory($directory); //这个其实没有任何作用 164 | $disk->deleteDirectory($directory); //删除目录,包括目录下所有子文件子目录 165 | 166 | $disk->uploadToken(); //获取上传Token 167 | $disk->uploadToken('file.jpg'); //获取上传Token 168 | 169 | $disk->withUploadToken($token); // 使用自定义的 uploadToken 进行上传, 170 | $disk->put('file.jpg',$content); // 则本次的 put 操作,将使用上述的 $token 进行上传。 171 | // 常用于自动触发持久化处理 https://github.com/qiniu/php-sdk/blob/master/examples/upload_and_pfop.php 172 | 173 | $disk->downloadUrl('file.jpg'); //获取下载地址 174 | $disk->downloadUrl('file.jpg') 175 | ->setDownload('foo.jpg'); //获取下载地址,文件名为 foo.jpg 176 | $disk->downloadUrl('file.jpg', 'https'); //获取HTTPS下载地址 177 | $disk->privateDownloadUrl('file.jpg'); //获取私有bucket下载地址 178 | $disk->privateDownloadUrl('file.jpg?attname=foo.jpg'); 179 | //获取私有bucket下载地址,文件名为 foo.jpg 180 | $disk->privateDownloadUrl('file.jpg', 'https'); //获取私有bucket的HTTPS下载地址 181 | $disk->privateDownloadUrl('file.jpg', 182 | [ 183 | 'domain'=>'https', 184 | 'expires'=>3600 185 | ]); //获取私有bucket的HTTPS下载地址。超时 3600 秒。 186 | $disk->avInfo('file.mp3'); //获取多媒体文件信息 187 | $disk->imageInfo('file.jpg'); //获取图片信息 188 | $disk->imageExif('file.jpg'); //获取图片EXIF信息 189 | $disk->imagePreviewUrl('file.jpg','imageView2/0/w/100/h/200'); //获取图片预览URL 190 | $disk->privateImagePreviewUrl('file.jpg','imageView2/0/w/100/h/200'); //获取私有bucket图片预览URL 191 | $disk->verifyCallback('application/x-www-form-urlencoded', $request->header('Authorization'), 'callback url', $request->getContent());//验证回调内容是否合法 192 | $disk->persistentFop('file.flv','avthumb/m3u8/segtime/40/vcodec/libx264/s/320x240'); //执行持久化数据处理 193 | $disk->persistentFop('file.flv','fop','队列名'); //使用私有队列执行持久化数据处理 194 | $disk->persistentStatus($persistent_fop_id); //查看持久化数据处理的状态。 195 | 196 | $disk->fetch('http://abc.com/foo.jpg', 'bar.jpg'); //调用fetch将 foo.jpg 数据以 bar.jpg 的名字储存起来。 197 | $disk->qetag(); //得到最后一次执行 put, copy, append 等写入操作后,得到的hash值。详见 https://github.com/qiniu/qetag 198 | $disk->lastReturn();//得到最后一次执行 put, copy, append 等写入操作后,得到的返回值。 199 | 200 | ``` 201 | 202 | 203 | ## 官方SDK / 手册 204 | 205 | - https://github.com/qiniu/php-sdk 206 | - http://developer.qiniu.com/docs/v6/sdk/php-sdk.html 207 | 208 | 209 | -------------------------------------------------------------------------------- /src/QiniuAdapter.php: -------------------------------------------------------------------------------- 1 | access_key = $access_key; 62 | $this->secret_key = $secret_key; 63 | $this->bucket = $bucket; 64 | $this->domains = $domains; 65 | $this->setPathPrefix('http://' . $this->domains['default']); 66 | $this->setDomainPrefix('http://' . $this->domains['default'], 'default'); 67 | $this->setDomainPrefix('https://' . $this->domains['https'], 'https'); 68 | $this->setDomainPrefix('http://' . $this->domains['custom'], 'custom'); 69 | $this->notify_url = $notify_url; 70 | $this->access = $access; 71 | $this->hotlinkPreventionKey = $hotlinkPreventionKey; 72 | } 73 | 74 | /** 75 | * Set the path prefix. 76 | * 77 | * @param string $prefix 78 | * 79 | * @return self 80 | */ 81 | public function setDomainPrefix($prefix, $domainType) 82 | { 83 | $is_empty = empty($prefix); 84 | 85 | if (!$is_empty) { 86 | $prefix = rtrim($prefix, $this->pathSeparator) . $this->pathSeparator; 87 | } 88 | 89 | $prefixedDomain = $is_empty ? null : $prefix; 90 | $this->prefixedDomains[$domainType] = $prefixedDomain; 91 | } 92 | 93 | public function withUploadToken($token) 94 | { 95 | $this->uploadToken = $token; 96 | } 97 | 98 | private function getAuth() 99 | { 100 | if ($this->auth == null) { 101 | $this->auth = new Auth($this->access_key, $this->secret_key); 102 | } 103 | 104 | return $this->auth; 105 | } 106 | 107 | private function getUploadManager() 108 | { 109 | if ($this->upload_manager == null) { 110 | $this->upload_manager = new UploadManager(); 111 | } 112 | 113 | return $this->upload_manager; 114 | } 115 | 116 | private function getBucketManager() 117 | { 118 | if ($this->bucket_manager == null) { 119 | $this->bucket_manager = new BucketManager($this->getAuth()); 120 | } 121 | 122 | return $this->bucket_manager; 123 | } 124 | 125 | private function getOperation() 126 | { 127 | if ($this->operation == null) { 128 | $this->operation = new Operation( 129 | $this->domains['default'], 130 | $this->access === self::ACCESS_PUBLIC ? null : $this->getAuth() 131 | ); 132 | } 133 | 134 | return $this->operation; 135 | } 136 | 137 | private function logQiniuError(Error $error, $extra = null) 138 | { 139 | \Log::error('Qiniu: ' . $error->code() . ' ' . $error->message() . '. ' . $extra); 140 | } 141 | 142 | /** 143 | * Update a file. 144 | * 145 | * @param string $path 146 | * @param string $contents 147 | * @param Config $config Config object 148 | * 149 | * @return array|false false on failure file meta data on success 150 | */ 151 | public function update($path, $contents, Config $config) 152 | { 153 | return $this->write($path, $contents, $config); 154 | } 155 | 156 | /** 157 | * Rewrite Qiniu\Storage\UploadManager::putFile 158 | * @param $upToken 159 | * @param $key 160 | * @param $fileResource 161 | * @param null $params 162 | * @param string $mime 163 | * @param bool $checkCrc 164 | * @return mixed 165 | * @throws \Exception 166 | */ 167 | private function qiniuPutFile( 168 | $upToken, 169 | $key, 170 | $fileResource, 171 | $params = null, 172 | $mime = 'application/octet-stream', 173 | $checkCrc = false 174 | ) 175 | { 176 | if ($fileResource === false) { 177 | throw new \Exception("file can not open", 1); 178 | } 179 | $file = $fileResource; 180 | $params = UploadManager::trimParams($params); 181 | $stat = fstat($file); 182 | $size = $stat['size']; 183 | if ($size <= QiniuConfig::BLOCK_SIZE) { 184 | $data = fread($file, $size); 185 | fclose($file); 186 | if ($data === false) { 187 | throw new \Exception("file can not read", 1); 188 | } 189 | $result = FormUploader::put( 190 | $upToken, 191 | $key, 192 | $data, 193 | new QiniuConfig(), 194 | $params, 195 | $mime, 196 | basename($key) 197 | ); 198 | return $result; 199 | } 200 | $up = new ResumeUploader( 201 | $upToken, 202 | $key, 203 | $file, 204 | $size, 205 | $params, 206 | $mime, 207 | new QiniuConfig() 208 | ); 209 | $ret = $up->upload(basename($key)); 210 | fclose($file); 211 | return $ret; 212 | } 213 | 214 | 215 | /** 216 | * Fetch a file. 217 | * 218 | * @DriverFunction 219 | * @param string $url 220 | * @param string $key 221 | * 222 | * @return bool|array 223 | */ 224 | public function fetch($url, $key = null) 225 | { 226 | $bucketMgr = $this->getBucketManager(); 227 | 228 | [$ret, $error] = $bucketMgr->fetch($url, $this->bucket, $key); 229 | if ($error !== null) { 230 | $this->logQiniuError($error, $this->bucket . '/' . $key); 231 | 232 | return false; 233 | } else { 234 | return $ret; 235 | } 236 | } 237 | 238 | /** 239 | * Create a directory. 240 | * 241 | * @param string $dirname directory name 242 | * @param Config $config 243 | * 244 | * @return array|false 245 | */ 246 | public function createDir($dirname, Config $config) 247 | { 248 | return ['path' => $dirname]; 249 | } 250 | 251 | 252 | /** 253 | * Get all the meta data of a file or directory. 254 | * 255 | * @param string $path 256 | * 257 | * @return array|false 258 | */ 259 | private function getMetadata($path) 260 | { 261 | $bucketMgr = $this->getBucketManager(); 262 | 263 | [$ret, $error] = $bucketMgr->stat($this->bucket, $path); 264 | if ($error !== null) { 265 | return false; 266 | } else { 267 | return $ret; 268 | } 269 | } 270 | 271 | /** 272 | * @DriverFunction 273 | * @param null $path 274 | * @param string $domainType 275 | * @return string|QiniuUrl 276 | */ 277 | public function downloadUrl($path = null, $domainType = 'default') 278 | { 279 | if ($this->access == self::ACCESS_PRIVATE) { 280 | return $this->privateDownloadUrl($path, $domainType); 281 | } 282 | $this->pathPrefix = $this->prefixedDomains[$domainType]; 283 | $location = $this->applyPathPrefix($path); 284 | $location = new QiniuUrl($location, $this->hotlinkPreventionKey); 285 | 286 | return $location; 287 | } 288 | 289 | /** 290 | * @DriverFunction 291 | * @param mixed $path 292 | * @return string 293 | */ 294 | public function getUrl($path) 295 | { 296 | if (is_string($path)) { 297 | return $this->downloadUrl($path, 'default')->getUrl(); 298 | } 299 | 300 | if (is_array($path)) { 301 | return $this->downloadUrl($path['path'], $path['domainType'])->getUrl(); 302 | } 303 | 304 | return $this->downloadUrl('', 'default')->getUrl(); 305 | 306 | } 307 | 308 | /** 309 | * @DriverFunction 310 | * @param $path 311 | * @param string|array $settings ['domain'=>'default', 'expires'=>3600] 312 | * @return string 313 | */ 314 | public function privateDownloadUrl($path, $settings = 'default') 315 | { 316 | $expires = 3600; 317 | $domain = 'default'; 318 | if (is_array($settings)) { 319 | $expires = isset($settings['expires']) ? $settings['expires'] : $expires; 320 | $domain = isset($settings['domain']) ? $settings['domain'] : $domain; 321 | } else { 322 | $domain = $settings; 323 | } 324 | $this->pathPrefix = $this->prefixedDomains[$domain]; 325 | $auth = $this->getAuth(); 326 | $location = $this->applyPathPrefix($path); 327 | $authUrl = $auth->privateDownloadUrl($location, $expires); 328 | $authUrl = new QiniuUrl($authUrl); 329 | 330 | return $authUrl; 331 | } 332 | 333 | /** 334 | * @DriverFunction 335 | * @param null $path 336 | * @param null $fops 337 | * @param null $pipline 338 | * @param bool $force 339 | * @return bool 340 | */ 341 | public function persistentFop($path = null, $fops = null, $pipline = null, $force = false, $notifyUrl = null) 342 | { 343 | $auth = $this->getAuth(); 344 | 345 | $pfop = new PersistentFop($auth); 346 | 347 | $notifyUrl = is_null($notifyUrl) ? $this->notify_url : $notifyUrl; 348 | [$id, $error] = $pfop->execute($this->bucket, $path, $fops, $pipline, $notifyUrl, $force); 349 | 350 | if ($error != null) { 351 | $this->logQiniuError($error); 352 | 353 | return false; 354 | } else { 355 | return $id; 356 | } 357 | } 358 | 359 | /** 360 | * @DriverFunction 361 | * @param $id 362 | * @return array 363 | */ 364 | public function persistentStatus($id) 365 | { 366 | $auth = $this->getAuth(); 367 | $pfop = new PersistentFop($auth); 368 | return $pfop->status($id); 369 | } 370 | 371 | /** 372 | * @DriverFunction 373 | * @param null $path 374 | * @return bool 375 | */ 376 | public function avInfo($path = null) 377 | { 378 | $operation = $this->getOperation(); 379 | 380 | [$ret, $error] = $operation->execute($path, 'avinfo'); 381 | 382 | if ($error !== null) { 383 | $this->logQiniuError($error); 384 | 385 | return false; 386 | } else { 387 | return $ret; 388 | } 389 | } 390 | 391 | /** 392 | * @DriverFunction 393 | * @param null $path 394 | * @return bool 395 | */ 396 | public function imageInfo($path = null) 397 | { 398 | $operation = $this->getOperation(); 399 | 400 | [$ret, $error] = $operation->execute($path, 'imageInfo'); 401 | 402 | if ($error !== null) { 403 | $this->logQiniuError($error); 404 | 405 | return false; 406 | } else { 407 | return $ret; 408 | } 409 | } 410 | 411 | /** 412 | * @DriverFunction 413 | * @param null $path 414 | * @return bool 415 | */ 416 | public function imageExif($path = null) 417 | { 418 | $operation = $this->getOperation(); 419 | 420 | [$ret, $error] = $operation->execute($path, 'exif'); 421 | 422 | if ($error !== null) { 423 | $this->logQiniuError($error); 424 | 425 | return false; 426 | } else { 427 | return $ret; 428 | } 429 | } 430 | 431 | /** 432 | * @DriverFunction 433 | * @param null $path 434 | * @param null $ops 435 | * @return string|QiniuUrl 436 | */ 437 | public function imagePreviewUrl($path = null, $ops = null) 438 | { 439 | if ($this->access == self::ACCESS_PRIVATE) { 440 | return $this->privateImagePreviewUrl($path, $ops); 441 | } 442 | $operation = $this->getOperation(); 443 | $url = $operation->buildUrl($path, $ops); 444 | $url = new QiniuUrl($url, $this->hotlinkPreventionKey); 445 | 446 | return $url; 447 | } 448 | 449 | /** 450 | * @DriverFunction 451 | * @param null $path 452 | * @param null $ops 453 | * @return string|QiniuUrl 454 | */ 455 | public function privateImagePreviewUrl($path = null, $ops = null) 456 | { 457 | $auth = $this->getAuth(); 458 | $operation = $this->getOperation(); 459 | $url = $operation->buildUrl($path, $ops); 460 | $authUrl = $auth->privateDownloadUrl($url); 461 | $authUrl = new QiniuUrl($authUrl); 462 | 463 | return $authUrl; 464 | } 465 | 466 | /** 467 | * @DriverFunction 468 | * @param null $path 469 | * @param int $expires 470 | * @param null $policy 471 | * @param bool $strictPolicy 472 | * @return string 473 | */ 474 | public function uploadToken( 475 | $path = null, 476 | $expires = 3600, 477 | $policy = null, 478 | $strictPolicy = true 479 | ) 480 | { 481 | $auth = $this->getAuth(); 482 | 483 | $token = $auth->uploadToken( 484 | $this->bucket, 485 | $path, 486 | $expires, 487 | $policy, 488 | $strictPolicy 489 | ); 490 | 491 | return $token; 492 | } 493 | 494 | /** 495 | * @DriverFunction 496 | * @param $contentType 497 | * @param $originAuthorization 498 | * @param $url 499 | * @param $body 500 | * @return bool 501 | */ 502 | public function verifyCallback($contentType, $originAuthorization, $url, $body) 503 | { 504 | $auth = $this->getAuth(); 505 | 506 | return $auth->verifyCallback($contentType, $originAuthorization, $url, $body); 507 | } 508 | 509 | /** 510 | * @DriverFunction 511 | * @param $localFilePath 512 | * @return array 513 | */ 514 | public function calculateQetag($localFilePath) 515 | { 516 | return Etag::sum($localFilePath); 517 | } 518 | 519 | /** 520 | * @DriverFunction 521 | * @return null 522 | */ 523 | public function getLastQetag() 524 | { 525 | if ($this->lastReturn && isset($this->lastReturn['hash'])) { 526 | return $this->lastReturn['hash']; 527 | } 528 | return null; 529 | } 530 | 531 | /** 532 | * @DriverFunction 533 | * @return null 534 | */ 535 | public function getLastReturn() 536 | { 537 | return $this->lastReturn; 538 | } 539 | 540 | /** 541 | * Write a new file. 542 | * 543 | * @param string $path 544 | * @param string $contents 545 | * @param Config $config Config object 546 | * 547 | * @return array|false false on failure file meta data on success 548 | */ 549 | public function write(string $path, string $contents, Config $config): void 550 | { 551 | $auth = $this->getAuth(); 552 | 553 | $token = $this->uploadToken ?: $auth->uploadToken($this->bucket, $path); 554 | $this->withUploadToken(null); 555 | 556 | $params = $config->get('params', null); 557 | $mime = $config->get('mime', 'application/octet-stream'); 558 | $checkCrc = $config->get('checkCrc', false); 559 | 560 | $upload_manager = $this->getUploadManager(); 561 | [$ret, $error] = $upload_manager->put($token, $path, $contents, $params, $mime, $checkCrc); 562 | 563 | if ($error !== null) { 564 | $this->logQiniuError($error); 565 | throw UnableToWriteFile::atLocation($path, $error->message()); 566 | } else { 567 | $this->lastReturn = $ret; 568 | } 569 | } 570 | 571 | /** 572 | * Write using a stream. 573 | * 574 | * @param string $path 575 | * @param $contents 576 | * @param Config $config 577 | * 578 | * @return mixed false or file metadata 579 | * @throws \Exception 580 | */ 581 | public function writeStream(string $path, $contents, Config $config): void 582 | { 583 | $auth = $this->getAuth(); 584 | 585 | $token = $this->uploadToken ?: $auth->uploadToken($this->bucket, $path); 586 | $this->withUploadToken(null); 587 | 588 | $params = $config->get('params', null); 589 | $mime = $config->get('mime', 'application/octet-stream'); 590 | $checkCrc = $config->get('checkCrc', false); 591 | 592 | [$ret, $error] = $this->qiniuPutFile($token, $path, $contents, $params, $mime, $checkCrc); 593 | 594 | if ($error !== null) { 595 | $this->logQiniuError($error); 596 | } else { 597 | $this->lastReturn = $ret; 598 | } 599 | } 600 | 601 | /** 602 | * Read a file. 603 | * 604 | * @param string $path 605 | * 606 | * @return array|false 607 | */ 608 | public function read(string $path): string 609 | { 610 | $location = $this->applyPathPrefix($path); 611 | $content = file_get_contents($location); 612 | if (false === $content) { 613 | throw UnableToReadFile::fromLocation($path); 614 | } 615 | return $content; 616 | } 617 | 618 | public function readStream(string $path) 619 | { 620 | if (ini_get('allow_url_fopen')) { 621 | if ($result = fopen($this->getUrl($path), 'r')) { 622 | return $result; 623 | } 624 | } 625 | 626 | throw UnableToReadFile::fromLocation($path); 627 | } 628 | 629 | 630 | /** 631 | * List contents of a directory. 632 | * 633 | * @param string $path 634 | * @param bool $deep 635 | * @return array 636 | */ 637 | public function listContents(string $path, bool $deep): iterable 638 | { 639 | $bucketMgr = $this->getBucketManager(); 640 | 641 | [$ret, $error] = $bucketMgr->listFiles($this->bucket, $path); 642 | $items = @$ret['items']; 643 | $marker = @$ret['marker']; 644 | $commonPrefixes = @$ret['commonPrefixes']; 645 | if ($error !== null) { 646 | $this->logQiniuError($error); 647 | 648 | return []; 649 | } else { 650 | $contents = []; 651 | foreach ($items as $item) { 652 | $normalized = [ 653 | 'type' => 'file', 654 | 'path' => $item['key'], 655 | 'timestamp' => $item['putTime'], 656 | ]; 657 | 658 | if ($normalized['type'] === 'file') { 659 | $normalized['size'] = $item['fsize']; 660 | } 661 | 662 | array_push($contents, $normalized); 663 | } 664 | 665 | return $contents; 666 | } 667 | } 668 | 669 | /** 670 | * Copy a file. 671 | * 672 | * @param string $source 673 | * @param string $destination 674 | * @param Config $config 675 | * @return void 676 | */ 677 | public function copy(string $source, string $destination, Config $config): void 678 | { 679 | $bucketMgr = $this->getBucketManager(); 680 | 681 | [$ret, $error] = $bucketMgr->copy($this->bucket, $source, $this->bucket, $destination); 682 | if ($error !== null) { 683 | $this->logQiniuError($error); 684 | throw UnableToCopyFile::fromLocationTo($source, $destination); 685 | } 686 | } 687 | 688 | /** 689 | * Delete a file. 690 | * 691 | * @param string $path 692 | * 693 | * @return bool 694 | */ 695 | public function delete(string $path): void 696 | { 697 | $bucketMgr = $this->getBucketManager(); 698 | 699 | [$ret, $error] = $bucketMgr->delete($this->bucket, $path); 700 | if ($error !== null) { 701 | $this->logQiniuError($error, $this->bucket . '/' . $path); 702 | throw UnableToDeleteFile::atLocation($path); 703 | } 704 | } 705 | 706 | public function fileExists(string $path): bool 707 | { 708 | $meta = $this->getMetadata($path); 709 | if ($meta) { 710 | return true; 711 | } 712 | 713 | return false; 714 | } 715 | 716 | public function directoryExists(string $path): bool 717 | { 718 | return $this->fileExists($path); 719 | } 720 | 721 | public function deleteDirectory(string $path): void 722 | { 723 | $this->delete($path); 724 | } 725 | 726 | public function createDirectory(string $path, Config $config): void 727 | { 728 | // Do not need to create directory. Just use write() to save your content. 729 | } 730 | 731 | public function setVisibility(string $path, string $visibility): void 732 | { 733 | throw UnableToSetVisibility::atLocation($path); 734 | } 735 | 736 | public function visibility(string $path): FileAttributes 737 | { 738 | throw UnableToSetVisibility::atLocation($path); 739 | } 740 | 741 | public function mimeType(string $path): FileAttributes 742 | { 743 | $stat = $this->getMetadata($path); 744 | if ($stat) { 745 | return new FileAttributes($path, null, null, null, $stat['mimeType']); 746 | } 747 | throw UnableToRetrieveMetadata::mimeType($path); 748 | } 749 | 750 | public function lastModified(string $path): FileAttributes 751 | { 752 | $stat = $this->getMetadata($path); 753 | if ($stat) { 754 | return new FileAttributes($path, null, null, $stat['putTime']); 755 | } 756 | throw UnableToRetrieveMetadata::mimeType($path); 757 | } 758 | 759 | public function fileSize(string $path): FileAttributes 760 | { 761 | $stat = $this->getMetadata($path); 762 | if ($stat) { 763 | return new FileAttributes($path, $stat['fsize']); 764 | } 765 | throw UnableToRetrieveMetadata::mimeType($path); 766 | } 767 | 768 | public function move(string $source, string $destination, Config $config): void 769 | { 770 | $bucketMgr = $this->getBucketManager(); 771 | [$ret, $error] = $bucketMgr->move($this->bucket, $source, $this->bucket, $destination); 772 | if ($error !== null) { 773 | $this->logQiniuError($error); 774 | throw UnableToMoveFile::fromLocationTo($source, $destination); 775 | } 776 | } 777 | 778 | /** 779 | * @var string|null path prefix 780 | */ 781 | protected $pathPrefix; 782 | 783 | /** 784 | * @var string 785 | */ 786 | protected $pathSeparator = '/'; 787 | 788 | /** 789 | * Set the path prefix. 790 | * 791 | * @param string $prefix 792 | * 793 | * @return void 794 | */ 795 | public function setPathPrefix($prefix) 796 | { 797 | $prefix = (string)$prefix; 798 | 799 | if ($prefix === '') { 800 | $this->pathPrefix = null; 801 | return; 802 | } 803 | 804 | $this->pathPrefix = rtrim($prefix, '\\/') . $this->pathSeparator; 805 | } 806 | 807 | /** 808 | * Get the path prefix. 809 | * 810 | * @return string|null path prefix or null if pathPrefix is empty 811 | */ 812 | public function getPathPrefix() 813 | { 814 | return $this->pathPrefix; 815 | } 816 | 817 | /** 818 | * Prefix a path. 819 | * 820 | * @param string $path 821 | * 822 | * @return string prefixed path 823 | */ 824 | public function applyPathPrefix($path) 825 | { 826 | return $this->getPathPrefix() . ltrim($path, '\\/'); 827 | } 828 | 829 | } 830 | --------------------------------------------------------------------------------