├── Action.php ├── Mysql.sql ├── Plugin.php ├── README.md ├── SQLite.sql ├── cloud ├── cos │ ├── include.php │ └── qcloudcos │ │ ├── auth.php │ │ ├── conf.php │ │ ├── cosapi.php │ │ ├── error_code.php │ │ ├── http_client.php │ │ ├── libcurl_helper.php │ │ ├── libcurl_wrapper.php │ │ └── slice_uploading.php ├── nos │ ├── autoload.php │ └── src │ │ └── NOS │ │ ├── Core │ │ ├── MimeTypes.php │ │ ├── NosException.php │ │ └── NosUtil.php │ │ ├── Http │ │ ├── LICENSE │ │ ├── RequestCore.php │ │ ├── RequestCore_Exception.php │ │ └── ResponseCore.php │ │ ├── Model │ │ ├── BucketInfo.php │ │ ├── BucketListInfo.php │ │ ├── DeleteFailedInfo.php │ │ ├── ListMultipartUploadInfo.php │ │ ├── ListPartsInfo.php │ │ ├── ObjectInfo.php │ │ ├── ObjectListInfo.php │ │ ├── PartInfo.php │ │ ├── UploadInfo.php │ │ └── XmlConfig.php │ │ ├── NosClient.php │ │ └── Result │ │ ├── BodyResult.php │ │ ├── ExistResult.php │ │ ├── GetLocationResult.php │ │ ├── GetObjectMetaResult.php │ │ ├── InitiateMultipartUploadResult.php │ │ ├── ListBucketsResult.php │ │ ├── ListMultipartUploadResult.php │ │ ├── ListObjectsResult.php │ │ ├── ListPartsResult.php │ │ ├── MultiDeleteResult.php │ │ ├── ObjDeduplicateResult.php │ │ ├── PutSetDeleteResult.php │ │ ├── Result.php │ │ ├── UploadPartResult.php │ │ ├── aclResult.php │ │ └── statusResult.php ├── qiniu │ ├── autoload.php │ └── src │ │ └── Qiniu │ │ ├── Auth.php │ │ ├── Config.php │ │ ├── Etag.php │ │ ├── Http │ │ ├── Client.php │ │ ├── Error.php │ │ ├── Request.php │ │ └── Response.php │ │ ├── Processing │ │ ├── ImageUrlBuilder.php │ │ ├── Operation.php │ │ └── PersistentFop.php │ │ ├── Storage │ │ ├── BucketManager.php │ │ ├── FormUploader.php │ │ ├── ResumeUploader.php │ │ └── UploadManager.php │ │ ├── Zone.php │ │ └── functions.php └── scs │ └── SCS.php ├── css ├── border-anim-h.gif ├── border-anim-v.gif ├── graphics │ ├── close.png │ ├── closeX.png │ ├── controlbar-black-border.gif │ ├── controlbar-text-buttons.png │ ├── controlbar-white-small.gif │ ├── controlbar-white.gif │ ├── controlbar2.gif │ ├── controlbar3.gif │ ├── controlbar4-hover.gif │ ├── controlbar4.gif │ ├── fullexpand.gif │ ├── geckodimmer.png │ ├── icon.gif │ ├── loader.gif │ ├── loader.white.gif │ ├── outlines │ │ ├── beveled.png │ │ ├── drop-shadow.png │ │ ├── glossy-dark.png │ │ ├── outer-glow.png │ │ ├── rounded-black.png │ │ └── rounded-white.png │ ├── resize.gif │ ├── scrollarrows.png │ ├── zoomin.cur │ └── zoomout.cur ├── highslide-ie6.css ├── highslide.css └── imgareaselect-animated.css ├── js ├── highslide-full.packed.js ├── highslide-with-gallery.packed.js ├── highslide-with-html.packed.js ├── highslide.packed.js └── imgareaselect.js └── manage-gallery.php /Action.php: -------------------------------------------------------------------------------- 1 | validate()) { 18 | $this->response->goBack(); 19 | } 20 | 21 | $gallery = $this->request->from('thumb','image','description','sort','name'); 22 | $gallery['order'] = $this->db->fetchObject($this->db->select(array('MAX(order)'=>'maxOrder'))->from('table.gallery'))->maxOrder+1; 23 | $gallery['gid'] = $this->db->query($this->db->insert('table.gallery')->rows($gallery)); 24 | 25 | //返回提示信息 26 | $this->widget('Widget_Notice')->highlight('gid-'.$gallery['gid']); 27 | $this->widget('Widget_Notice')->set(_t('相册组%s图片 %s 添加成功',''.$gallery['sort'].'',''.$gallery['name'].''),'success'); 28 | $this->response->redirect(Typecho_Common::url('extending.php?panel=HighSlide%2Fmanage-gallery.php&group='.$gallery['sort'],$this->options->adminUrl)); 29 | } 30 | 31 | /** 32 | * 更新相册图片 33 | * 34 | * @access public 35 | * @return void 36 | */ 37 | public function updategallery() 38 | { 39 | if (HighSlide_Plugin::form('update')->validate()) { 40 | $this->response->goBack(); 41 | } 42 | 43 | $gallery = $this->request->from('gid','thumb','image','description','sort','name'); 44 | $this->db->query($this->db->update('table.gallery')->rows($gallery)->where('gid = ?',$gallery['gid'])); 45 | 46 | //返回提示信息 47 | $this->widget('Widget_Notice')->highlight('gid-'.$gallery['gid']); 48 | $this->widget('Widget_Notice')->set(_t('相册组%s图片 %s 修改成功',''.$gallery['sort'].'',''.$gallery['name'].''),'success'); 49 | $this->response->redirect(Typecho_Common::url('extending.php?panel=HighSlide%2Fmanage-gallery.php&group='.$gallery['sort'],$this->options->adminUrl)); 50 | } 51 | 52 | /** 53 | * 移除相册图片 54 | * 55 | * @access public 56 | * @return void 57 | */ 58 | public function deletegallery() 59 | { 60 | $gids = $this->request->filter('int')->getArray('gid'); 61 | $group = isset($this->request->group) ? $this->request->filter('int')->group : HighSlide_Plugin::defaultsort(); 62 | 63 | $deletecount = 0; 64 | foreach ($gids as $gid) { 65 | if ($this->db->query($this->db->delete('table.gallery')->where('gid = ?',$gid))) { 66 | ++$deletecount; 67 | } 68 | } 69 | 70 | //返回提示信息 71 | $this->widget('Widget_Notice')->set($deletecount>0 ? _t('图片已从相册移除') : _t('没有图片被移除'),$deletecount>0 ? 'success' : 'notice'); 72 | $this->response->redirect(Typecho_Common::url('extending.php?panel=HighSlide%2Fmanage-gallery.php&group='.$group,$this->options->adminUrl)); 73 | } 74 | 75 | /** 76 | * 排序相册图片 77 | * 78 | * @access public 79 | * @return void 80 | */ 81 | public function sortgallery() 82 | { 83 | $gids = $this->request->filter('int')->getArray('gid'); 84 | 85 | foreach ($gids as $sort=>$gid) { 86 | $this->db->query($this->db->update('table.gallery')->rows(array('order'=>$sort+1))->where('gid = ?',$gid)); 87 | } 88 | 89 | //返回提示信息 90 | if (!$this->request->isAjax()) { 91 | $this->response->goBack(); 92 | } else { 93 | $this->response->throwJson(array('success'=>1,'message'=>_t('图片排序完成'))); 94 | } 95 | } 96 | 97 | /** 98 | * 执行上传图片 99 | * 100 | * @access public 101 | * @return void 102 | */ 103 | public function uploadimage() 104 | { 105 | if (!empty($_FILES)) { 106 | $file = array_pop($_FILES); 107 | if (0==$file['error'] && is_uploaded_file($file['tmp_name'])) { 108 | //xhr的send无法支持utf8 109 | if ($this->request->isAjax()) { 110 | $file['name'] = urldecode($file['name']); 111 | } 112 | 113 | $result = HighSlide_Plugin::uploadhandle($file); 114 | 115 | if (false!==$result) { 116 | $this->response->throwJson(array(array( 117 | 'name'=>$result['name'], 118 | 'title'=>$result['title'], 119 | 'bytes'=>number_format(ceil($result['size']/1024)).' Kb' 120 | ))); 121 | } 122 | } 123 | } 124 | 125 | $this->response->throwJson(false); 126 | } 127 | 128 | /** 129 | * 执行删除图片 130 | * 131 | * @access public 132 | * @return void 133 | */ 134 | public function removeimage() 135 | { 136 | $requests = $this->request->from('imgname','url'); 137 | 138 | if ($requests['imgname']) { 139 | HighSlide_Plugin::removehandle($requests['imgname'],false,$requests['url']); 140 | } 141 | 142 | $this->response->throwJson(false); 143 | } 144 | 145 | /** 146 | * 执行缩略图片 147 | * 148 | * @access public 149 | * @return void 150 | */ 151 | public function cropthumbnail() 152 | { 153 | $requests = $this->request->from('imgname','w','h','x1','y1','url'); 154 | $isatt = isset($this->request->tid); 155 | 156 | if ($requests['imgname']) { 157 | $result = HighSlide_Plugin::crophandle($requests['imgname'],$requests['w'],$requests['h'],$requests['x1'],$requests['y1'],$requests['url'],$isatt); 158 | $bytes = number_format(ceil($result['size']/1024)).' Kb'; 159 | $tid = ''; 160 | 161 | //附件模式归档 162 | if ($isatt) { 163 | $tid = $this->request->filter('int')->tid; 164 | $widget = Typecho_Widget::widget('Widget_Abstract_Contents'); 165 | 166 | if ($tid) { //修改 167 | $widget->update(array('text'=>serialize($result)),$this->db->sql()->where('cid = ?',$tid)); 168 | $this->db->fetchRow($widget->select()->where('table.contents.cid = ?',$tid) 169 | ->where('table.contents.type = ?', 'attachment'), array($widget, 'push')); 170 | } else { //新建 171 | $struct = array( 172 | 'title'=>$result['name'], 173 | 'slug' =>$result['name'], 174 | 'type' =>'attachment', 175 | 'status'=>'publish', 176 | 'text' =>serialize($result), 177 | 'allowComment' =>1, 178 | 'allowPing'=>0, 179 | 'allowFeed'=>1 180 | ); 181 | if (isset($this->request->cid)) { 182 | $cid = $this->request->filter('int')->cid; 183 | if ($widget->isWriteable($this->db->sql()->where('cid = ?', $cid))) { 184 | $struct['parent'] = $cid; 185 | } 186 | } 187 | 188 | $tid = $widget->insert($struct); 189 | $this->db->fetchRow($widget->select()->where('table.contents.cid = ?', $tid) 190 | ->where('table.contents.type = ?', 'attachment'), array($widget, 'push')); 191 | } 192 | } 193 | 194 | $this->response->throwJson(array('cid'=>$tid,'bytes'=>$bytes,'aurl'=>$result['aurl'])); 195 | } 196 | 197 | $this->response->throwJson(false); 198 | } 199 | 200 | /** 201 | * 同步插件设置 202 | * 203 | * @access public 204 | * @return void 205 | */ 206 | public function syncsettings() 207 | { 208 | //验证规格表单 209 | $validator = new Typecho_Validate(); 210 | $validator->addRule('fixedwidth','isInteger',_t('固定宽度请填写整数数字')); 211 | $validator->addRule('fixedheight','isInteger',_t('固定高度请填写整数数字')); 212 | $validator->addRule('fixedratio',array(new HighSlide_Plugin,'ratioformat'),_t('固定比例请填写:号与数字')); 213 | $validator->addRule('fixedwidth','required',_t('固定宽度不能为空')); 214 | $validator->addRule('fixedheight','required',_t('固定高度不能为空')); 215 | $validator->addRule('fixedratio','required',_t('固定比例不能为空')); 216 | if ($error = $validator->run($this->request->from('fixedwidth','fixedheight','fixedratio'))) { 217 | $this->widget('Widget_Notice')->set($error,'error'); 218 | $this->response->goBack(); 219 | } 220 | 221 | //保存提交数据 222 | Helper::configPlugin('HighSlide',$this->request->from( 223 | 'gallery','thumbfix','fixedwidth','fixedheight','fixedratio', 224 | 'storage','thumbapi','path','cloudtoo', 225 | 'qiniubucket','qiniudomain','qiniuak','qiniusk', 226 | 'scsbucket','scsdomain','scsimgx','scsak','scssk', 227 | 'nosbucket','nosdomain','nosak','nosas','nosep', 228 | 'cosbucket','cosdomain','cosai','cossi','cossk','cosrg' 229 | )); 230 | 231 | //返回提示信息 232 | $this->widget('Widget_Notice')->set(_t('相册设置已保存'),'success'); 233 | $this->response->goBack(); 234 | } 235 | 236 | /** 237 | * 预览内文附件 238 | * 239 | * @access public 240 | * @return void 241 | */ 242 | public function postpreview() 243 | { 244 | $settings = $this->options->plugin('HighSlide'); 245 | $local = $this->options->siteUrl; 246 | 247 | //获取附件对象 248 | if (isset($this->request->cid)) { 249 | $cid = $this->request->filter('int')->cid; 250 | $attachment = Typecho_Widget::widget('Widget_Contents_Attachment_Related','parentId='.$cid); 251 | } else { 252 | $attachment = Typecho_Widget::widget('Widget_Contents_Attachment_Unattached'); 253 | } 254 | 255 | //重构响应数据 256 | $aurl = ''; 257 | $attachurl = ''; 258 | $title= ''; 259 | $name = ''; 260 | $parse = ''; 261 | $path = ''; 262 | $url = ''; 263 | $imgurl = ''; 264 | $struct =array(); 265 | while ($attachment->next()) { 266 | $aurl = $attachment->attachment->aurl; 267 | $attachurl = $attachment->attachment->url; 268 | $title= $attachment->attachment->name; 269 | $name = basename($attachurl); 270 | //获取API文件名 271 | if ($aurl) { 272 | $parse = parse_url($attachurl); 273 | $name = basename($parse['path']); 274 | } 275 | $path = strstr($attachment->attachment->path,$name,true); 276 | $url = Typecho_Common::url($path,$settings->cloudtoo ? HighSlide_Plugin::route()->site : $local); 277 | //探测绝对地址 278 | if (!$aurl) { 279 | $imgurl = HighSlide_Plugin::ifexist($attachurl); 280 | if (!$imgurl) { 281 | $imgurl = HighSlide_Plugin::ifexist($url.$name); 282 | if (!$imgurl) { 283 | $imgurl = $local.$path.$name; 284 | } 285 | } 286 | } 287 | $struct[] = array( 288 | 'cid'=>$attachment->cid, 289 | 'isimg'=>$attachment->attachment->isImage ? 1 : 0, 290 | 'name'=>$name, 291 | 'title'=>$title, 292 | 'url'=>$aurl ? $aurl : $imgurl, 293 | 'size'=>number_format(ceil($attachment->attachment->size/1024)).' KB', 294 | 'turl'=>$settings->cloudtoo && $settings->thumbapi ? str_replace('thumb_','',$name) : $url.(0===strpos($name,'thumb_') ? $name : 'thumb_'.$name), 295 | 'aurl'=>$aurl 296 | ); 297 | } 298 | if (!isset($this->request->cid)) { 299 | sort($struct); //修正排序 300 | } 301 | 302 | $this->response->throwJson(Json::encode($struct)); 303 | } 304 | 305 | /** 306 | * 绑定动作 307 | * 308 | * @access public 309 | * @return void 310 | */ 311 | public function action() 312 | { 313 | $this->db = Typecho_Db::get(); 314 | $this->options = Helper::options(); 315 | $this->security = Helper::security(); 316 | 317 | $this->security->protect(); 318 | $this->on($this->request->is('do=insert'))->insertgallery(); 319 | $this->on($this->request->is('do=update'))->updategallery(); 320 | $this->on($this->request->is('do=delete'))->deletegallery(); 321 | $this->on($this->request->is('do=sort'))->sortgallery(); 322 | $this->on($this->request->is('do=upload'))->uploadimage(); 323 | $this->on($this->request->is('do=remove'))->removeimage(); 324 | $this->on($this->request->is('do=crop'))->cropthumbnail(); 325 | $this->on($this->request->is('do=sync'))->syncsettings(); 326 | $this->on($this->request->is('do=preview'))->postpreview(); 327 | 328 | $this->response->redirect($this->options->adminUrl); 329 | } 330 | 331 | } -------------------------------------------------------------------------------- /Mysql.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `typecho_gallery` ( 2 | `gid` int(10) unsigned NOT NULL auto_increment COMMENT 'gallery表主键', 3 | `thumb` varchar(200) default NULL COMMENT '缩略图', 4 | `image` varchar(200) default NULL COMMENT '原图', 5 | `sort` int(10) default '0' COMMENT '相册组', 6 | `name` varchar(200) default NULL COMMENT '图片名称', 7 | `description` varchar(200) default NULL COMMENT '图片描述', 8 | `order` int(10) unsigned default '0' COMMENT '图片排序', 9 | PRIMARY KEY (`gid`) 10 | ) ENGINE=MYISAM DEFAULT CHARSET=%charset%; 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Typecho弹窗相册插件HighSlide 2 | 2018年7月16日更新至**v1.4.7**: 3 | - 使用5.0.0packed双内核 4 | - 附件栏内集成缩略图模式 5 | - 附件缩略图支持归档联动 6 | - 优化相册的修改模式机制 7 | - 支持4家免费云储存及API 8 | - 增加html弹窗编辑器按钮 9 | - 修正MD转义及检测等bug 10 | 11 | #### 详细说明与效果演示见blog发布地址: 12 | > http://www.yzmb.me/archives/net/highslide-for-typecho -------------------------------------------------------------------------------- /SQLite.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE `typecho_gallery` ( 2 | `gid` INTEGER NOT NULL PRIMARY KEY, 3 | `thumb` varchar(200) default NULL, 4 | `image` varchar(200) default NULL, 5 | `sort` int(10) default '0', 6 | `name` varchar(200) default NULL, 7 | `description` varchar(200) default NULL, 8 | `order` int(10) default '0' 9 | ); 10 | -------------------------------------------------------------------------------- /cloud/cos/include.php: -------------------------------------------------------------------------------- 1 | plugin('HighSlide'); 22 | self::$APPID = $settings->cosai; 23 | self::$SECRET_ID = $settings->cossi; 24 | self::$SECRET_KEY = $settings->cossk; 25 | } 26 | 27 | /** 28 | * Get the User-Agent string to send to COS server. 29 | */ 30 | public static function getUserAgent() { 31 | return 'cos-php-sdk-' . self::VERSION; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /cloud/cos/qcloudcos/error_code.php: -------------------------------------------------------------------------------- 1 | value fields to post. 6 | * @return $boundary and encoded post fields. 7 | */ 8 | function buildCustomPostFields($fields) { 9 | // invalid characters for "name" and "filename" 10 | static $disallow = array("\0", "\"", "\r", "\n"); 11 | 12 | // initialize body 13 | $body = array(); 14 | 15 | // build normal parameters 16 | foreach ($fields as $key => $value) { 17 | $key = str_replace($disallow, "_", $key); 18 | $body[] = implode("\r\n", array( 19 | "Content-Disposition: form-data; name=\"{$key}\"", 20 | '', 21 | filter_var($value), 22 | )); 23 | } 24 | 25 | // generate safe boundary 26 | do { 27 | $boundary = "---------------------" . md5(mt_rand() . microtime()); 28 | } while (preg_grep("/{$boundary}/", $body)); 29 | 30 | // add boundary for each parameters 31 | foreach ($body as &$part) { 32 | $part = "--{$boundary}\r\n{$part}"; 33 | } 34 | unset($part); 35 | 36 | // add final boundary 37 | $body[] = "--{$boundary}--"; 38 | $body[] = ''; 39 | 40 | return array($boundary, implode("\r\n", $body)); 41 | } 42 | -------------------------------------------------------------------------------- /cloud/cos/qcloudcos/libcurl_wrapper.php: -------------------------------------------------------------------------------- 1 | curlMultiHandle = curl_multi_init(); 30 | $this->idleCurlHandle = array(); 31 | } 32 | 33 | public function __destruct() { 34 | curl_multi_close($this->curlMultiHandle); 35 | foreach ($this->idleCurlHandle as $handle) { 36 | curl_close($handle); 37 | } 38 | $this->idleCurlHandle = array(); 39 | } 40 | 41 | public function startSendingRequest($httpRequest, $done) { 42 | if (count($this->idleCurlHandle) !== 0) { 43 | $curlHandle = array_pop($this->idleCurlHandle); 44 | } else { 45 | $curlHandle = curl_init(); 46 | if ($curlHandle === false) { 47 | return false; 48 | } 49 | } 50 | 51 | curl_setopt($curlHandle, CURLOPT_TIMEOUT_MS, $httpRequest->timeoutMs); 52 | curl_setopt($curlHandle, CURLOPT_URL, $httpRequest->url); 53 | curl_setopt($curlHandle, CURLOPT_HEADER, 1); 54 | curl_setopt($curlHandle, CURLOPT_RETURNTRANSFER, 1); 55 | $headers = $httpRequest->customHeaders; 56 | array_push($headers, 'User-Agent:'.Conf::getUserAgent()); 57 | if ($httpRequest->method === 'POST') { 58 | if (defined('CURLOPT_SAFE_UPLOAD')) { 59 | curl_setopt($curlHandle, CURLOPT_SAFE_UPLOAD, true); 60 | } 61 | 62 | curl_setopt($curlHandle, CURLOPT_POST, true); 63 | $arr = buildCustomPostFields($httpRequest->dataToPost); 64 | array_push($headers, 'Expect: 100-continue'); 65 | array_push($headers, 'Content-Type: multipart/form-data; boundary=' . $arr[0]); 66 | curl_setopt($curlHandle, CURLOPT_POSTFIELDS, $arr[1]); 67 | } 68 | curl_setopt($curlHandle, CURLOPT_HTTPHEADER, $headers); 69 | 70 | curl_multi_add_handle($this->curlMultiHandle, $curlHandle); 71 | 72 | $this->curlHandleInfo[$curlHandle]['done'] = $done; 73 | $this->curlHandleInfo[$curlHandle]['request'] = $httpRequest; 74 | } 75 | 76 | public function performSendingRequest() { 77 | for (;;) { 78 | $active = null; 79 | 80 | do { 81 | $mrc = curl_multi_exec($this->curlMultiHandle, $active); 82 | $info = curl_multi_info_read($this->curlMultiHandle); 83 | if ($info !== false) { 84 | $this->processResult($info); 85 | } 86 | } while ($mrc == CURLM_CALL_MULTI_PERFORM); 87 | 88 | while ($active && $mrc == CURLM_OK) { 89 | if (curl_multi_select($this->curlMultiHandle) == -1) { 90 | usleep(1); 91 | } 92 | 93 | do { 94 | $mrc = curl_multi_exec($this->curlMultiHandle, $active); 95 | $info = curl_multi_info_read($this->curlMultiHandle); 96 | if ($info !== false) { 97 | $this->processResult($info); 98 | } 99 | } while ($mrc == CURLM_CALL_MULTI_PERFORM); 100 | } 101 | 102 | if (count($this->curlHandleInfo) == 0) { 103 | break; 104 | } 105 | } 106 | } 107 | 108 | private function processResult($info) { 109 | $result = $info['result']; 110 | $handle = $info['handle']; 111 | $request = $this->curlHandleInfo[$handle]['request']; 112 | $done = $this->curlHandleInfo[$handle]['done']; 113 | $response = new HttpResponse(); 114 | 115 | if ($result !== CURLE_OK) { 116 | $response->curlErrorCode = $result; 117 | $response->curlErrorMessage = curl_error($handle); 118 | 119 | call_user_func($done, $request, $response); 120 | } else { 121 | $responseStr = curl_multi_getcontent($handle); 122 | $headerSize = curl_getinfo($handle, CURLINFO_HEADER_SIZE); 123 | $headerStr = substr($responseStr, 0, $headerSize); 124 | $body = substr($responseStr, $headerSize); 125 | 126 | $response->curlErrorCode = curl_errno($handle); 127 | $response->curlErrorMessage = curl_error($handle); 128 | $response->statusCode = curl_getinfo($handle, CURLINFO_HTTP_CODE); 129 | $headLines = explode("\r\n", $headerStr); 130 | foreach ($headLines as $head) { 131 | $arr = explode(':', $head); 132 | if (count($arr) >= 2) { 133 | $response->headers[trim($arr[0])] = trim($arr[1]); 134 | } 135 | } 136 | $response->body = $body; 137 | 138 | call_user_func($done, $request, $response); 139 | } 140 | 141 | unset($this->curlHandleInfo[$handle]); 142 | curl_multi_remove_handle($this->curlMultiHandle, $handle); 143 | 144 | array_push($this->idleCurlHandle, $handle); 145 | } 146 | 147 | private function resetCurl($handle) { 148 | if (function_exists('curl_reset')) { 149 | curl_reset($handle); 150 | } else { 151 | curl_setopt($handler, CURLOPT_URL, ''); 152 | curl_setopt($handler, CURLOPT_HTTPHEADER, array()); 153 | curl_setopt($handler, CURLOPT_POSTFIELDS, array()); 154 | curl_setopt($handler, CURLOPT_TIMEOUT, 0); 155 | curl_setopt($handler, CURLOPT_SSL_VERIFYPEER, false); 156 | curl_setopt($handler, CURLOPT_SSL_VERIFYHOST, 0); 157 | } 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /cloud/cos/qcloudcos/slice_uploading.php: -------------------------------------------------------------------------------- 1 | timeoutMs = $timeoutMs; 45 | $this->maxRetryCount = $maxRetryCount; 46 | $this->errorCode = COSAPI_SUCCESS; 47 | $this->errorMessage = ''; 48 | $this->concurrentTaskNumber = self::DEFAULT_CONCURRENT_TASK_NUMBER; 49 | 50 | $this->offset = 0; 51 | 52 | $this->libcurlWrapper = new LibcurlWrapper(); 53 | } 54 | 55 | public function __destruct() { 56 | } 57 | 58 | public function getLastErrorCode() { 59 | return $this->errorCode; 60 | } 61 | 62 | public function getLastErrorMessage() { 63 | return $this->errorMessage; 64 | } 65 | 66 | public function getRequestId() { 67 | return $this->requestId; 68 | } 69 | 70 | public function getAccessUrl() { 71 | return $this->accessUrl; 72 | } 73 | 74 | public function getResourcePath() { 75 | return $this->resourcePath; 76 | } 77 | 78 | public function getSourceUrl() { 79 | return $this->sourceUrl; 80 | } 81 | 82 | /** 83 | * Return true on success and return false on failure. 84 | */ 85 | public function initUploading( 86 | $signature, $srcFpath, $url, $fileSize, $sliceSize, $bizAttr, $insertOnly) { 87 | $this->signature = $signature; 88 | $this->srcFpath = $srcFpath; 89 | $this->url = $url; 90 | $this->fileSize = $fileSize; 91 | $this->sliceSize = $sliceSize; 92 | 93 | // Clear error so caller can successfully retry. 94 | $this->clearError(); 95 | 96 | $request = array( 97 | 'url' => $url, 98 | 'method' => 'post', 99 | 'timeout' => $this->timeoutMs / 1000, 100 | 'data' => array( 101 | 'op' => 'upload_slice_init', 102 | 'filesize' => $fileSize, 103 | 'slice_size' => $sliceSize, 104 | 'insertOnly' => $insertOnly, 105 | ), 106 | 'header' => array( 107 | 'Authorization: ' . $signature, 108 | ), 109 | ); 110 | 111 | if (isset($bizAttr) && strlen($bizAttr)) { 112 | $request['data']['biz_attr'] = $bizAttr; 113 | } 114 | 115 | $response = $this->sendRequest($request); 116 | if ($response === false) { 117 | return false; 118 | } 119 | $this->session = $response['data']['session']; 120 | 121 | if (isset($response['data']['slice_size'])) { 122 | $this->sliceSize = $response['data']['slice_size']; 123 | } 124 | 125 | if (isset($response['data']['serial_upload']) && $response['data']['serial_upload'] == 1) { 126 | $this->concurrentTaskNumber = 1; 127 | } 128 | 129 | return true; 130 | } 131 | 132 | /** 133 | * Return true on success and return false on failure. 134 | */ 135 | public function performUploading() { 136 | for ($i = 0; $i < $this->concurrentTaskNumber; ++$i) { 137 | if ($this->offset >= $this->fileSize) { 138 | break; 139 | } 140 | 141 | $sliceContent = file_get_contents($this->srcFpath, false, null, $this->offset, $this->sliceSize); 142 | if ($sliceContent === false) { 143 | $this->setError(COSAPI_PARAMS_ERROR, 'read file ' . $this->srcFpath . ' error'); 144 | return false; 145 | } 146 | 147 | $request = new HttpRequest(); 148 | $request->timeoutMs = $this->timeoutMs; 149 | $request->url = $this->url; 150 | $request->method = 'POST'; 151 | $request->customHeaders = array( 152 | 'Authorization: ' . $this->signature, 153 | ); 154 | $request->dataToPost = array( 155 | 'op' => 'upload_slice_data', 156 | 'session' => $this->session, 157 | 'offset' => $this->offset, 158 | 'filecontent' => $sliceContent, 159 | 'datamd5' => md5($sliceContent), 160 | ); 161 | $request->userData = array( 162 | 'retryCount' => 0, 163 | ); 164 | 165 | $this->libcurlWrapper->startSendingRequest($request, array($this, 'uploadCallback')); 166 | 167 | $this->offset += $this->sliceSize; 168 | } 169 | 170 | $this->libcurlWrapper->performSendingRequest(); 171 | 172 | if ($this->errorCode !== COSAPI_SUCCESS) { 173 | return false; 174 | } 175 | 176 | return true; 177 | } 178 | 179 | /** 180 | * Return true on success and return false on failure. 181 | */ 182 | public function finishUploading() { 183 | $request = array( 184 | 'url' => $this->url, 185 | 'method' => 'post', 186 | 'timeout' => $this->timeoutMs / 1000, 187 | 'data' => array( 188 | 'op' => 'upload_slice_finish', 189 | 'session' => $this->session, 190 | 'filesize' => $this->fileSize, 191 | ), 192 | 'header' => array( 193 | 'Authorization: ' . $this->signature, 194 | ), 195 | ); 196 | 197 | $response = $this->sendRequest($request); 198 | if ($response === false) { 199 | return false; 200 | } 201 | 202 | $this->accessUrl = $response['data']['access_url']; 203 | $this->resourcePath = $response['data']['resource_path']; 204 | $this->sourceUrl = $response['data']['source_url']; 205 | 206 | return true; 207 | } 208 | 209 | private function sendRequest($request) { 210 | $response = HttpClient::sendRequest($request); 211 | if ($response === false) { 212 | $this->setError(COSAPI_NETWORK_ERROR, 'network error'); 213 | return false; 214 | } 215 | 216 | $responseJson = json_decode($response, true); 217 | if ($responseJson === NULL) { 218 | $this->setError(COSAPI_NETWORK_ERROR, 'network error'); 219 | return false; 220 | } 221 | 222 | $this->requestId = $responseJson['request_id']; 223 | if ($responseJson['code'] != 0) { 224 | $this->setError($responseJson['code'], $responseJson['message']); 225 | return false; 226 | } 227 | 228 | return $responseJson; 229 | } 230 | 231 | private function clearError() { 232 | $this->errorCode = COSAPI_SUCCESS; 233 | $this->errorMessage = 'success'; 234 | } 235 | 236 | private function setError($errorCode, $errorMessage) { 237 | $this->errorCode = $errorCode; 238 | $this->errorMessage = $errorMessage; 239 | } 240 | 241 | public function uploadCallback($request, $response) { 242 | if ($this->errorCode !== COSAPI_SUCCESS) { 243 | return; 244 | } 245 | 246 | $requestErrorCode = COSAPI_SUCCESS; 247 | $requestErrorMessage = 'success'; 248 | $retryCount = $request->userData['retryCount']; 249 | 250 | $responseJson = json_decode($response->body, true); 251 | if ($responseJson === NULL) { 252 | $requestErrorCode = COSAPI_NETWORK_ERROR; 253 | $requestErrorMessage = 'network error'; 254 | } 255 | 256 | if ($response->curlErrorCode !== CURLE_OK) { 257 | $requestErrorCode = COSAPI_NETWORK_ERROR; 258 | $requestErrorMessage = 'network error: curl errno ' . $response->curlErrorCode; 259 | } 260 | 261 | $this->requestId = $responseJson['request_id']; 262 | if ($responseJson['code'] != 0) { 263 | $requestErrorCode = $responseJson['code']; 264 | $requestErrorMessage = $responseJson['message']; 265 | } 266 | 267 | if (isset($responseJson['data']['datamd5']) && 268 | $responseJson['data']['datamd5'] !== $request->dataToPost['datamd5']) { 269 | $requestErrorCode = COSAPI_INTEGRITY_ERROR; 270 | $requestErrorMessage = 'cosapi integrity error'; 271 | } 272 | 273 | if ($requestErrorCode !== COSAPI_SUCCESS) { 274 | if ($retryCount >= $this->maxRetryCount) { 275 | $this->setError($requestErrorCode, $requestErrorMessage); 276 | } else { 277 | $request->userData['retryCount'] += 1; 278 | $this->libcurlWrapper->startSendingRequest($request, array($this, 'uploadCallback')); 279 | } 280 | return; 281 | } 282 | 283 | if ($this->offset >= $this->fileSize) { 284 | return; 285 | } 286 | 287 | // Send next slice. 288 | $nextSliceContent = file_get_contents($this->srcFpath, false, null, $this->offset, $this->sliceSize); 289 | if ($nextSliceContent === false) { 290 | $this->setError(COSAPI_PARAMS_ERROR, 'read file ' . $this->srcFpath . ' error'); 291 | return; 292 | } 293 | 294 | $nextSliceRequest = new HttpRequest(); 295 | $nextSliceRequest->timeoutMs = $this->timeoutMs; 296 | $nextSliceRequest->url = $this->url; 297 | $nextSliceRequest->method = 'POST'; 298 | $nextSliceRequest->customHeaders = array( 299 | 'Authorization: ' . $this->signature, 300 | ); 301 | $nextSliceRequest->dataToPost = array( 302 | 'op' => 'upload_slice_data', 303 | 'session' => $this->session, 304 | 'offset' => $this->offset, 305 | 'filecontent' => $nextSliceContent, 306 | 'datamd5' => md5($nextSliceContent), 307 | ); 308 | $nextSliceRequest->userData = array( 309 | 'retryCount' => 0, 310 | ); 311 | 312 | $this->libcurlWrapper->startSendingRequest($nextSliceRequest, array($this, 'uploadCallback')); 313 | 314 | $this->offset += $this->sliceSize; 315 | } 316 | } 317 | -------------------------------------------------------------------------------- /cloud/nos/autoload.php: -------------------------------------------------------------------------------- 1 | 1) { 24 | $ext = strtolower(end($parts)); 25 | if (isset(self::$mime_types[$ext])) { 26 | return self::$mime_types[$ext]; 27 | } 28 | } 29 | 30 | return null; 31 | } 32 | 33 | private static $mime_types = array( 34 | 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 35 | 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template', 36 | 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template', 37 | 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow', 38 | 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation', 39 | 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide', 40 | 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 41 | 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template', 42 | 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12', 43 | 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12', 44 | 'apk' => 'application/vnd.android.package-archive', 45 | 'hqx' => 'application/mac-binhex40', 46 | 'cpt' => 'application/mac-compactpro', 47 | 'doc' => 'application/msword', 48 | 'ogg' => 'audio/ogg', 49 | 'pdf' => 'application/pdf', 50 | 'rtf' => 'text/rtf', 51 | 'mif' => 'application/vnd.mif', 52 | 'xls' => 'application/vnd.ms-excel', 53 | 'ppt' => 'application/vnd.ms-powerpoint', 54 | 'odc' => 'application/vnd.oasis.opendocument.chart', 55 | 'odb' => 'application/vnd.oasis.opendocument.database', 56 | 'odf' => 'application/vnd.oasis.opendocument.formula', 57 | 'odg' => 'application/vnd.oasis.opendocument.graphics', 58 | 'otg' => 'application/vnd.oasis.opendocument.graphics-template', 59 | 'odi' => 'application/vnd.oasis.opendocument.image', 60 | 'odp' => 'application/vnd.oasis.opendocument.presentation', 61 | 'otp' => 'application/vnd.oasis.opendocument.presentation-template', 62 | 'ods' => 'application/vnd.oasis.opendocument.spreadsheet', 63 | 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', 64 | 'odt' => 'application/vnd.oasis.opendocument.text', 65 | 'odm' => 'application/vnd.oasis.opendocument.text-master', 66 | 'ott' => 'application/vnd.oasis.opendocument.text-template', 67 | 'oth' => 'application/vnd.oasis.opendocument.text-web', 68 | 'sxw' => 'application/vnd.sun.xml.writer', 69 | 'stw' => 'application/vnd.sun.xml.writer.template', 70 | 'sxc' => 'application/vnd.sun.xml.calc', 71 | 'stc' => 'application/vnd.sun.xml.calc.template', 72 | 'sxd' => 'application/vnd.sun.xml.draw', 73 | 'std' => 'application/vnd.sun.xml.draw.template', 74 | 'sxi' => 'application/vnd.sun.xml.impress', 75 | 'sti' => 'application/vnd.sun.xml.impress.template', 76 | 'sxg' => 'application/vnd.sun.xml.writer.global', 77 | 'sxm' => 'application/vnd.sun.xml.math', 78 | 'sis' => 'application/vnd.symbian.install', 79 | 'wbxml' => 'application/vnd.wap.wbxml', 80 | 'wmlc' => 'application/vnd.wap.wmlc', 81 | 'wmlsc' => 'application/vnd.wap.wmlscriptc', 82 | 'bcpio' => 'application/x-bcpio', 83 | 'torrent' => 'application/x-bittorrent', 84 | 'bz2' => 'application/x-bzip2', 85 | 'vcd' => 'application/x-cdlink', 86 | 'pgn' => 'application/x-chess-pgn', 87 | 'cpio' => 'application/x-cpio', 88 | 'csh' => 'application/x-csh', 89 | 'dvi' => 'application/x-dvi', 90 | 'spl' => 'application/x-futuresplash', 91 | 'gtar' => 'application/x-gtar', 92 | 'hdf' => 'application/x-hdf', 93 | 'jar' => 'application/java-archive', 94 | 'jnlp' => 'application/x-java-jnlp-file', 95 | 'js' => 'application/javascript', 96 | 'json' => 'application/json', 97 | 'ksp' => 'application/x-kspread', 98 | 'chrt' => 'application/x-kchart', 99 | 'kil' => 'application/x-killustrator', 100 | 'latex' => 'application/x-latex', 101 | 'rpm' => 'application/x-rpm', 102 | 'sh' => 'application/x-sh', 103 | 'shar' => 'application/x-shar', 104 | 'swf' => 'application/x-shockwave-flash', 105 | 'sit' => 'application/x-stuffit', 106 | 'sv4cpio' => 'application/x-sv4cpio', 107 | 'sv4crc' => 'application/x-sv4crc', 108 | 'tar' => 'application/x-tar', 109 | 'tcl' => 'application/x-tcl', 110 | 'tex' => 'application/x-tex', 111 | 'man' => 'application/x-troff-man', 112 | 'me' => 'application/x-troff-me', 113 | 'ms' => 'application/x-troff-ms', 114 | 'ustar' => 'application/x-ustar', 115 | 'src' => 'application/x-wais-source', 116 | 'zip' => 'application/zip', 117 | 'm3u' => 'audio/x-mpegurl', 118 | 'ra' => 'audio/x-pn-realaudio', 119 | 'wav' => 'audio/x-wav', 120 | 'wma' => 'audio/x-ms-wma', 121 | 'wax' => 'audio/x-ms-wax', 122 | 'pdb' => 'chemical/x-pdb', 123 | 'xyz' => 'chemical/x-xyz', 124 | 'bmp' => 'image/bmp', 125 | 'gif' => 'image/gif', 126 | 'ief' => 'image/ief', 127 | 'png' => 'image/png', 128 | 'wbmp' => 'image/vnd.wap.wbmp', 129 | 'ras' => 'image/x-cmu-raster', 130 | 'pnm' => 'image/x-portable-anymap', 131 | 'pbm' => 'image/x-portable-bitmap', 132 | 'pgm' => 'image/x-portable-graymap', 133 | 'ppm' => 'image/x-portable-pixmap', 134 | 'rgb' => 'image/x-rgb', 135 | 'xbm' => 'image/x-xbitmap', 136 | 'xpm' => 'image/x-xpixmap', 137 | 'xwd' => 'image/x-xwindowdump', 138 | 'css' => 'text/css', 139 | 'rtx' => 'text/richtext', 140 | 'tsv' => 'text/tab-separated-values', 141 | 'jad' => 'text/vnd.sun.j2me.app-descriptor', 142 | 'wml' => 'text/vnd.wap.wml', 143 | 'wmls' => 'text/vnd.wap.wmlscript', 144 | 'etx' => 'text/x-setext', 145 | 'mxu' => 'video/vnd.mpegurl', 146 | 'flv' => 'video/x-flv', 147 | 'wm' => 'video/x-ms-wm', 148 | 'wmv' => 'video/x-ms-wmv', 149 | 'wmx' => 'video/x-ms-wmx', 150 | 'wvx' => 'video/x-ms-wvx', 151 | 'avi' => 'video/x-msvideo', 152 | 'movie' => 'video/x-sgi-movie', 153 | 'ice' => 'x-conference/x-cooltalk', 154 | '3gp' => 'video/3gpp', 155 | 'ai' => 'application/postscript', 156 | 'aif' => 'audio/x-aiff', 157 | 'aifc' => 'audio/x-aiff', 158 | 'aiff' => 'audio/x-aiff', 159 | 'asc' => 'text/plain', 160 | 'atom' => 'application/atom+xml', 161 | 'au' => 'audio/basic', 162 | 'bin' => 'application/octet-stream', 163 | 'cdf' => 'application/x-netcdf', 164 | 'cgm' => 'image/cgm', 165 | 'class' => 'application/octet-stream', 166 | 'dcr' => 'application/x-director', 167 | 'dif' => 'video/x-dv', 168 | 'dir' => 'application/x-director', 169 | 'djv' => 'image/vnd.djvu', 170 | 'djvu' => 'image/vnd.djvu', 171 | 'dll' => 'application/octet-stream', 172 | 'dmg' => 'application/octet-stream', 173 | 'dms' => 'application/octet-stream', 174 | 'dtd' => 'application/xml-dtd', 175 | 'dv' => 'video/x-dv', 176 | 'dxr' => 'application/x-director', 177 | 'eps' => 'application/postscript', 178 | 'exe' => 'application/octet-stream', 179 | 'ez' => 'application/andrew-inset', 180 | 'gram' => 'application/srgs', 181 | 'grxml' => 'application/srgs+xml', 182 | 'gz' => 'application/x-gzip', 183 | 'htm' => 'text/html', 184 | 'html' => 'text/html', 185 | 'ico' => 'image/x-icon', 186 | 'ics' => 'text/calendar', 187 | 'ifb' => 'text/calendar', 188 | 'iges' => 'model/iges', 189 | 'igs' => 'model/iges', 190 | 'jp2' => 'image/jp2', 191 | 'jpe' => 'image/jpeg', 192 | 'jpeg' => 'image/jpeg', 193 | 'jpg' => 'image/jpeg', 194 | 'kar' => 'audio/midi', 195 | 'lha' => 'application/octet-stream', 196 | 'lzh' => 'application/octet-stream', 197 | 'm4a' => 'audio/mp4a-latm', 198 | 'm4p' => 'audio/mp4a-latm', 199 | 'm4u' => 'video/vnd.mpegurl', 200 | 'm4v' => 'video/x-m4v', 201 | 'mac' => 'image/x-macpaint', 202 | 'mathml' => 'application/mathml+xml', 203 | 'mesh' => 'model/mesh', 204 | 'mid' => 'audio/midi', 205 | 'midi' => 'audio/midi', 206 | 'mov' => 'video/quicktime', 207 | 'mp2' => 'audio/mpeg', 208 | 'mp3' => 'audio/mpeg', 209 | 'mp4' => 'video/mp4', 210 | 'mpe' => 'video/mpeg', 211 | 'mpeg' => 'video/mpeg', 212 | 'mpg' => 'video/mpeg', 213 | 'mpga' => 'audio/mpeg', 214 | 'msh' => 'model/mesh', 215 | 'nc' => 'application/x-netcdf', 216 | 'oda' => 'application/oda', 217 | 'ogv' => 'video/ogv', 218 | 'pct' => 'image/pict', 219 | 'pic' => 'image/pict', 220 | 'pict' => 'image/pict', 221 | 'pnt' => 'image/x-macpaint', 222 | 'pntg' => 'image/x-macpaint', 223 | 'ps' => 'application/postscript', 224 | 'qt' => 'video/quicktime', 225 | 'qti' => 'image/x-quicktime', 226 | 'qtif' => 'image/x-quicktime', 227 | 'ram' => 'audio/x-pn-realaudio', 228 | 'rdf' => 'application/rdf+xml', 229 | 'rm' => 'application/vnd.rn-realmedia', 230 | 'roff' => 'application/x-troff', 231 | 'sgm' => 'text/sgml', 232 | 'sgml' => 'text/sgml', 233 | 'silo' => 'model/mesh', 234 | 'skd' => 'application/x-koan', 235 | 'skm' => 'application/x-koan', 236 | 'skp' => 'application/x-koan', 237 | 'skt' => 'application/x-koan', 238 | 'smi' => 'application/smil', 239 | 'smil' => 'application/smil', 240 | 'snd' => 'audio/basic', 241 | 'so' => 'application/octet-stream', 242 | 'svg' => 'image/svg+xml', 243 | 't' => 'application/x-troff', 244 | 'texi' => 'application/x-texinfo', 245 | 'texinfo' => 'application/x-texinfo', 246 | 'tif' => 'image/tiff', 247 | 'tiff' => 'image/tiff', 248 | 'tr' => 'application/x-troff', 249 | 'txt' => 'text/plain', 250 | 'vrml' => 'model/vrml', 251 | 'vxml' => 'application/voicexml+xml', 252 | 'webm' => 'video/webm', 253 | 'webp' => 'image/webp', 254 | 'wrl' => 'model/vrml', 255 | 'xht' => 'application/xhtml+xml', 256 | 'xhtml' => 'application/xhtml+xml', 257 | 'xml' => 'application/xml', 258 | 'xsl' => 'application/xml', 259 | 'xslt' => 'application/xslt+xml', 260 | 'xul' => 'application/vnd.mozilla.xul+xml', 261 | ); 262 | } -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Core/NosException.php: -------------------------------------------------------------------------------- 1 | details = $details; 24 | } else { 25 | $message = $details; 26 | parent::__construct($message); 27 | } 28 | } 29 | 30 | public function getHTTPStatus() 31 | { 32 | return isset($this->details['status']) ? $this->details['status'] : ''; 33 | } 34 | 35 | public function getRequestId() 36 | { 37 | return isset($this->details['request-id']) ? $this->details['request-id'] : ''; 38 | } 39 | 40 | public function getErrorCode() 41 | { 42 | return isset($this->details['code']) ? $this->details['code'] : ''; 43 | } 44 | 45 | public function getErrorMessage() 46 | { 47 | return isset($this->details['message']) ? $this->details['message'] : ''; 48 | } 49 | 50 | public function getDetails() 51 | { 52 | return isset($this->details['body']) ? $this->details['body'] : ''; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Core/NosUtil.php: -------------------------------------------------------------------------------- 1 | $value) { 37 | if (is_string($key) && ! is_array($value)) { 38 | $temp[] = rawurlencode($key) . '=' . rawurlencode($value); 39 | } 40 | } 41 | return implode('&', $temp); 42 | } 43 | 44 | /** 45 | * 转义字符替换 46 | * 47 | * @param string $subject 48 | * @return string 49 | */ 50 | public static function sReplace($subject) 51 | { 52 | $search = array('&','<','>','\'','"'); 53 | $replace = array('&','<','>',''','"'); 54 | return str_replace($search, $replace, $subject); 55 | } 56 | 57 | /** 58 | * 检查是否是中文编码 59 | * 60 | * @param 61 | * $str 62 | * @return int 63 | */ 64 | public static function chkChinese($str) 65 | { 66 | return preg_match('/[\x80-\xff]./', $str); 67 | } 68 | 69 | /** 70 | * 检测是否GB2312编码 71 | * 72 | * @param string $str 73 | * @return boolean false UTF-8编码 TRUE GB2312编码 74 | */ 75 | public static function isGb2312($str) 76 | { 77 | for ($i = 0; $i < strlen($str); $i ++) { 78 | $v = ord($str[$i]); 79 | if ($v > 127) { 80 | if (($v >= 228) && ($v <= 233)) { 81 | if (($i + 2) >= (strlen($str) - 1)) 82 | return true; // not enough characters 83 | $v1 = ord($str[$i + 1]); 84 | $v2 = ord($str[$i + 2]); 85 | if (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) 86 | return false; 87 | else 88 | return true; 89 | } 90 | } 91 | } 92 | return false; 93 | } 94 | 95 | /** 96 | * 检测是否GBK编码 97 | * 98 | * @param string $str 99 | * @param boolean $gbk 100 | * @return boolean 101 | */ 102 | public static function checkChar($str, $gbk = true) 103 | { 104 | for ($i = 0; $i < strlen($str); $i ++) { 105 | $v = ord($str[$i]); 106 | if ($v > 127) { 107 | if (($v >= 228) && ($v <= 233)) { 108 | if (($i + 2) >= (strlen($str) - 1)) 109 | return $gbk ? true : FALSE; // not enough characters 110 | $v1 = ord($str[$i + 1]); 111 | $v2 = ord($str[$i + 2]); 112 | if ($gbk) { 113 | return (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) ? FALSE : TRUE; // GBK 114 | } else { 115 | return (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) ? TRUE : FALSE; 116 | } 117 | } 118 | } 119 | } 120 | return $gbk ? TRUE : FALSE; 121 | } 122 | 123 | /** 124 | * 检验bucket名称是否合法 125 | * bucket的命名规范: 126 | * 1. 127 | * 只能包括小写字母,数字,-,. 128 | * 2. 必须以小写字母或者数字开头 129 | * 3. 长度必须在3-63字节之间 130 | * 131 | * @param string $bucket Bucket名称 132 | * @return boolean 133 | */ 134 | public static function validateBucket($bucket) 135 | { 136 | $pattern = '/^[a-z0-9][a-z0-9-\.]{2,62}$/'; 137 | if (! preg_match($pattern, $bucket)) { 138 | return false; 139 | } 140 | return true; 141 | } 142 | 143 | /** 144 | * 检验object名称是否合法 145 | * object命名规范: 146 | * 1. 147 | * 规则长度必须在1-1000字节之间 148 | * 2. 使用UTF-8编码 149 | * 150 | * @param string $object 151 | * Object名称 152 | * @return boolean 153 | */ 154 | public static function validateObject($object) 155 | { 156 | $pattern = '/^.{1,1000}$/'; 157 | if (empty($object) || ! preg_match($pattern, $object) || self::startsWith($object, '/') || self::startsWith($object, '\\')) { 158 | return false; 159 | } 160 | return true; 161 | } 162 | 163 | /** 164 | * 判断字符串$str是不是以$findMe开始 165 | * 166 | * @param string $str 167 | * @param string $findMe 168 | * @return bool 169 | */ 170 | public static function startsWith($str, $findMe) 171 | { 172 | if (strpos($str, $findMe) === 0) { 173 | return true; 174 | } else { 175 | return false; 176 | } 177 | } 178 | 179 | /** 180 | * 检验$options 181 | * 182 | * @param array $options 183 | * @throws NOSException 184 | * @return boolean 185 | */ 186 | public static function validateOptions($options) 187 | { 188 | // $options 189 | if ($options != NULL && ! is_array($options)) { 190 | throw new NosException($options . ':' . 'option must be array'); 191 | } 192 | } 193 | 194 | /** 195 | * 检查上传文件的内容是否合法 196 | * 197 | * @param $content string 198 | * @throws NOSException 199 | */ 200 | public static function validateContent($content) 201 | { 202 | if (empty($content)) { 203 | throw new NosException("http body content is invalid"); 204 | } 205 | } 206 | 207 | /** 208 | * 校验BUCKET/OBJECT/OBJECT GROUP是否为空 209 | * 210 | * @param string $name 211 | * @param string $errMsg 212 | * @throws NOSException 213 | * @return void 214 | */ 215 | public static function throwNOSExceptionWithMessageIfEmpty($name, $errMsg) 216 | { 217 | if (empty($name)) { 218 | throw new NosException($errMsg); 219 | } 220 | } 221 | 222 | /** 223 | * 仅供测试使用的接口,请勿使用 224 | * 225 | * @param 226 | * $filename 227 | * @param 228 | * $size 229 | */ 230 | public static function generateFile($filename, $size) 231 | { 232 | if (file_exists($filename) && $size == filesize($filename)) { 233 | echo $filename . " already exists, no need to create again. "; 234 | return; 235 | } 236 | $part_size = 1 * 1024 * 1024; 237 | $fp = fopen($filename, "w"); 238 | $characters = << 0) { 245 | if ($size < $part_size) { 246 | $write_size = $size; 247 | } else { 248 | $write_size = $part_size; 249 | } 250 | $size -= $write_size; 251 | $a = $characters[rand(0, $charactersLength - 1)]; 252 | $content = str_repeat($a, $write_size); 253 | $flag = fwrite($fp, $content); 254 | if (! $flag) { 255 | echo "write to " . $filename . " failed.
"; 256 | break; 257 | } 258 | } 259 | } else { 260 | echo "open " . $filename . " failed.
"; 261 | } 262 | fclose($fp); 263 | } 264 | 265 | /** 266 | * 得到文件的md5编码 267 | * 268 | * @param 269 | * $filename 270 | * @param 271 | * $from_pos 272 | * @param 273 | * $to_pos 274 | * @return string 275 | */ 276 | public static function getMd5SumForFile($filename, $from_pos, $to_pos) 277 | { 278 | $content_md5 = ""; 279 | if (($to_pos - $from_pos) > self::NOS_MAX_PART_SIZE) { 280 | return $content_md5; 281 | } 282 | $filesize = filesize($filename); 283 | if ($from_pos >= $filesize || $to_pos >= $filesize || $from_pos < 0 || $to_pos < 0) { 284 | return $content_md5; 285 | } 286 | 287 | $total_length = $to_pos - $from_pos + 1; 288 | $buffer = 8192; 289 | $left_length = $total_length; 290 | if (! file_exists($filename)) { 291 | return $content_md5; 292 | } 293 | 294 | if (false === $fh = fopen($filename, 'rb')) { 295 | return $content_md5; 296 | } 297 | 298 | fseek($fh, $from_pos); 299 | $data = ''; 300 | while (! feof($fh)) { 301 | if ($left_length >= $buffer) { 302 | $read_length = $buffer; 303 | } else { 304 | $read_length = $left_length; 305 | } 306 | if ($read_length <= 0) { 307 | break; 308 | } else { 309 | $data .= fread($fh, $read_length); 310 | $left_length = $left_length - $read_length; 311 | } 312 | } 313 | fclose($fh); 314 | $content_md5 = md5($data); 315 | return $content_md5; 316 | } 317 | 318 | /** 319 | * 检测是否windows系统,因为windows系统默认编码为GBK 320 | * 321 | * @return bool 322 | */ 323 | public static function isWin() 324 | { 325 | return strtoupper(substr(PHP_OS, 0, 3)) == "WIN"; 326 | } 327 | 328 | /** 329 | * 主要是由于windows系统编码是gbk,遇到中文时候,如果不进行转换处理会出现找不到文件的问题 330 | * 331 | * @param 332 | * $file_path 333 | * @return string 334 | */ 335 | public static function encodePath($file_path) 336 | { 337 | if (self::chkChinese($file_path) && self::isWin()) { 338 | $file_path = iconv('utf-8', 'gbk', $file_path); 339 | } 340 | return $file_path; 341 | } 342 | 343 | /** 344 | * 判断用户输入的endpoint是否是 xxx.xxx.xxx.xxx:port 或者 xxx.xxx.xxx.xxx的ip格式 345 | * 346 | * @param string $endpoint 347 | * 需要做判断的endpoint 348 | * @return boolean 349 | */ 350 | public static function isIPFormat($endpoint) 351 | { 352 | $ip_array = explode(":", $endpoint); 353 | $hostname = $ip_array[0]; 354 | $ret = filter_var($hostname, FILTER_VALIDATE_IP); 355 | if (! $ret) { 356 | return false; 357 | } else { 358 | return true; 359 | } 360 | } 361 | 362 | public static function createPutBucketDuplicationXmlBody($duplication) 363 | { 364 | $xml = new \SimpleXMLElement(''); 365 | $xml->addChild('Status', $duplication); 366 | return trim($xml->asXML()); 367 | } 368 | 369 | public static function createPutBucketVersingXmlBody($versing) 370 | { 371 | $xml = new \SimpleXMLElement(''); 372 | $xml->addChild('Status', $versing); 373 | return trim($xml->asXML()); 374 | } 375 | 376 | /** 377 | * 378 | * @param unknown $key 379 | */ 380 | public static function creatPutBucketDefault404XmlBody($key) 381 | { 382 | $xml = new \SimpleXMLElement(''); 383 | $xml->addChild('Key', $key); 384 | return trim($xml->asXML()); 385 | } 386 | 387 | /** 388 | * 生成DeleteMultiObjects接口的xml消息 389 | * 390 | * @param string[] $objects 391 | * @param bool $quiet 392 | * @return string 393 | */ 394 | public static function createDeleteObjectsXmlBody($objects,$quite) 395 | { 396 | $xml = new \SimpleXMLElement(''); 397 | $xml->addChild('Quiet', $quite); 398 | foreach ($objects as $object) { 399 | $sub_object = $xml->addChild('Object'); 400 | $object = NosUtil::sReplace($object); 401 | $sub_object->addChild('Key', $object); 402 | } 403 | return trim($xml->asXML()); 404 | } 405 | 406 | /** 407 | * 生成CompleteMultipartUpload接口的xml消息 408 | * 409 | * @param array[] $listParts 410 | * @return string 411 | */ 412 | public static function createCompleteMultipartUploadXmlBody($listParts) 413 | { 414 | $xml = new \SimpleXMLElement(''); 415 | foreach ($listParts as $node) { 416 | $part = $xml->addChild('Part'); 417 | $part->addChild('PartNumber', $node['PartNumber']); 418 | $part->addChild('ETag', $node['ETag']); 419 | } 420 | return trim($xml->asXML()); 421 | } 422 | 423 | /** 424 | * 读取目录 425 | * 426 | * @param string $dir 427 | * @param string $exclude 428 | * @param bool $recursive 429 | * @return string[] 430 | */ 431 | public static function readDir($dir, $exclude = ".|..|.svn|.git", $recursive = false) 432 | { 433 | $file_list_array = array(); 434 | $base_path = $dir; 435 | $exclude_array = explode("|", $exclude); 436 | $exclude_array = array_unique(array_merge($exclude_array, array( 437 | '.', 438 | '..' 439 | ))); 440 | 441 | if ($recursive) { 442 | foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir)) as $new_file) { 443 | if ($new_file->isDir()) 444 | continue; 445 | $object = str_replace($base_path, '', $new_file); 446 | if (! in_array(strtolower($object), $exclude_array)) { 447 | $object = ltrim($object, '/'); 448 | if (is_file($new_file)) { 449 | $key = md5($new_file . $object, false); 450 | $file_list_array[$key] = array( 451 | 'path' => $new_file, 452 | 'file' => $object 453 | ); 454 | } 455 | } 456 | } 457 | } else 458 | if ($handle = opendir($dir)) { 459 | while (false !== ($file = readdir($handle))) { 460 | if (! in_array(strtolower($file), $exclude_array)) { 461 | $new_file = $dir . '/' . $file; 462 | $object = $file; 463 | $object = ltrim($object, '/'); 464 | if (is_file($new_file)) { 465 | $key = md5($new_file . $object, false); 466 | $file_list_array[$key] = array( 467 | 'path' => $new_file, 468 | 'file' => $object 469 | ); 470 | } 471 | } 472 | } 473 | closedir($handle); 474 | } 475 | return $file_list_array; 476 | } 477 | 478 | /** 479 | * 480 | * @param unknown $object 481 | * @return mixed 482 | */ 483 | public static function objectEncode($object) 484 | { 485 | return str_replace(array("+","%2A"),array("%20","*"), urlencode($object)); 486 | } 487 | } 488 | 489 | 490 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Http/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2010 Ryan Parman, Foleeo Inc., and contributors. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are 4 | permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of 7 | conditions and the following disclaimer. 8 | 9 | * Redistributions in binary form must reproduce the above copyright notice, this list 10 | of conditions and the following disclaimer in the documentation and/or other materials 11 | provided with the distribution. 12 | 13 | * Neither the name of Ryan Parman, Foleeo Inc. nor the names of its contributors may be used to 14 | endorse or promote products derived from this software without specific prior written 15 | permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 18 | OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 19 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 20 | AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 | POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Http/RequestCore_Exception.php: -------------------------------------------------------------------------------- 1 | ). 29 | * @param string $body (Required) XML-formatted response from AWS. 30 | * @param integer $status (Optional) HTTP response status code from the request. 31 | * @return Mixed Contains an `header` property (HTTP headers as an associative array), a or `body` property, and an `status` code. 32 | */ 33 | public function __construct($header, $body, $status = null) 34 | { 35 | $this->header = $header; 36 | $this->body = $body; 37 | $this->status = $status; 38 | 39 | return $this; 40 | } 41 | 42 | /** 43 | * Did we receive the status code we expected? 44 | * 45 | * @param integer|array $codes (Optional) The status code(s) to expect. Pass an for a single acceptable value, or an of integers for multiple acceptable values. 46 | * @return boolean Whether we received the expected status code or not. 47 | */ 48 | public function isOK($codes = array(200, 201, 204, 206)) 49 | { 50 | if (is_array($codes)) { 51 | return in_array($this->status, $codes); 52 | } 53 | 54 | return $this->status === $codes; 55 | } 56 | } -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Model/BucketInfo.php: -------------------------------------------------------------------------------- 1 | name = $name; 23 | $this->createDate = $createDate; 24 | } 25 | 26 | /** 27 | * 得到bucket的名称 28 | * 29 | * @return string 30 | */ 31 | public function getName() 32 | { 33 | return $this->name; 34 | } 35 | 36 | /** 37 | * 得到bucket的创建时间 38 | * 39 | * @return string 40 | */ 41 | public function getCreateDate() 42 | { 43 | return $this->createDate; 44 | } 45 | 46 | /** 47 | * bucket的名称 48 | * 49 | * @var string 50 | */ 51 | private $name; 52 | 53 | /** 54 | * bucket的创建事件 55 | * 56 | * @var string 57 | */ 58 | private $createDate; 59 | } -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Model/BucketListInfo.php: -------------------------------------------------------------------------------- 1 | bucketList = $bucketList; 21 | } 22 | 23 | /** 24 | * 得到BucketInfo列表 25 | * 26 | * @return BucketInfo[] 27 | */ 28 | public function getBucketList() 29 | { 30 | return $this->bucketList; 31 | } 32 | 33 | /** 34 | * BucketInfo信息列表 35 | * 36 | * @var array 37 | */ 38 | private $bucketList = array(); 39 | } -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Model/DeleteFailedInfo.php: -------------------------------------------------------------------------------- 1 | key = $key; 9 | $this->code = $code; 10 | $this->message = $message; 11 | } 12 | 13 | /** 14 | * @return the $key 15 | */ 16 | public function getKey() 17 | { 18 | return $this->key; 19 | } 20 | 21 | /** 22 | * @return the $code 23 | */ 24 | public function getCode() 25 | { 26 | return $this->code; 27 | } 28 | 29 | /** 30 | * @return the $message 31 | */ 32 | public function getMessage() 33 | { 34 | return $this->message; 35 | } 36 | 37 | /** 38 | * @param string $key 39 | */ 40 | public function setKey($key) 41 | { 42 | $this->key = $key; 43 | } 44 | 45 | /** 46 | * @param string $code 47 | */ 48 | public function setCode($code) 49 | { 50 | $this->code = $code; 51 | } 52 | 53 | /** 54 | * @param string $message 55 | */ 56 | public function setMessage($message) 57 | { 58 | $this->message = $message; 59 | } 60 | 61 | 62 | private $key = ''; 63 | private $code = ''; 64 | private $message = ''; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Model/ListMultipartUploadInfo.php: -------------------------------------------------------------------------------- 1 | bucket = $bucket; 10 | $this->nextKeyMarker = $nextKeyMarker; 11 | $this->uploads = $uploads; 12 | $this->isTruncated = $isTruncated; 13 | } 14 | 15 | /** 16 | * @return the $bucket 17 | */ 18 | public function getBucket() 19 | { 20 | return $this->bucket; 21 | } 22 | 23 | /** 24 | * @return the $isTruncted 25 | */ 26 | public function getIsTruncated() 27 | { 28 | return $this->isTruncated; 29 | } 30 | 31 | /** 32 | * @return the $nextKeyMarker 33 | */ 34 | public function getNextKeyMarker() 35 | { 36 | return $this->nextKeyMarker; 37 | } 38 | 39 | /** 40 | * @return the $uploads 41 | */ 42 | public function getUploads() 43 | { 44 | return $this->uploads; 45 | } 46 | 47 | private $bucket = ''; 48 | private $nextKeyMarker = ''; 49 | private $isTruncated = ''; 50 | private $uploads = array(); 51 | } 52 | 53 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Model/ListPartsInfo.php: -------------------------------------------------------------------------------- 1 | bucket = $bucket; 10 | $this->key = $key; 11 | $this->uploadId = $uploadId; 12 | $this->storageClass = $storageClass; 13 | $this->partNumberMarker = $partNumberMarker; 14 | $this->nextPartNumberMarker = $nextPartNumberMarker; 15 | $this->maxParts = $maxParts; 16 | $this->isTruncated = $isTruncated; 17 | $this->listPart = $listPart; 18 | } 19 | 20 | /** 21 | * @return the $bucket 22 | */ 23 | public function getBucket() 24 | { 25 | return $this->bucket; 26 | } 27 | 28 | /** 29 | * @return the $key 30 | */ 31 | public function getKey() 32 | { 33 | return $this->key; 34 | } 35 | 36 | /** 37 | * @return the $uploadId 38 | */ 39 | public function getUploadId() 40 | { 41 | return $this->uploadId; 42 | } 43 | 44 | /** 45 | * @return the $storageClass 46 | */ 47 | public function getStorageClass() 48 | { 49 | return $this->storageClass; 50 | } 51 | 52 | /** 53 | * @return the $partNumberMarker 54 | */ 55 | public function getPartNumberMarker() 56 | { 57 | return $this->partNumberMarker; 58 | } 59 | 60 | /** 61 | * @return the $nextPartNumberMarker 62 | */ 63 | public function getNextPartNumberMarker() 64 | { 65 | return $this->nextPartNumberMarker; 66 | } 67 | 68 | /** 69 | * @return the $maxParts 70 | */ 71 | public function getMaxParts() 72 | { 73 | return $this->maxParts; 74 | } 75 | 76 | /** 77 | * @return the $isTruncated 78 | */ 79 | public function getIsTruncated() 80 | { 81 | return $this->isTruncated; 82 | } 83 | 84 | /** 85 | * @return the $listPart 86 | */ 87 | public function getListPart() 88 | { 89 | return $this->listPart; 90 | } 91 | 92 | 93 | private $bucket = ''; 94 | private $key = ''; 95 | private $uploadId = ''; 96 | private $storageClass = ''; 97 | private $partNumberMarker = 0; 98 | private $nextPartNumberMarker = 0; 99 | private $maxParts = 0; 100 | private $isTruncated = NULL; 101 | private $listPart =array(); 102 | } 103 | 104 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Model/ObjectInfo.php: -------------------------------------------------------------------------------- 1 | key = $key; 32 | $this->lastModified = $lastModified; 33 | $this->eTag = $eTag; 34 | $this->size = $size; 35 | $this->storageClass = $storageClass; 36 | } 37 | 38 | /** 39 | * @return string 40 | */ 41 | public function getKey() 42 | { 43 | return $this->key; 44 | } 45 | 46 | /** 47 | * @return string 48 | */ 49 | public function getLastModified() 50 | { 51 | return $this->lastModified; 52 | } 53 | 54 | /** 55 | * @return string 56 | */ 57 | public function getETag() 58 | { 59 | return $this->eTag; 60 | } 61 | 62 | /** 63 | * @return int 64 | */ 65 | public function getSize() 66 | { 67 | return $this->size; 68 | } 69 | 70 | /** 71 | * @return string 72 | */ 73 | public function getStorageClass() 74 | { 75 | return $this->storageClass; 76 | } 77 | 78 | private $key = ""; 79 | private $lastModified = ""; 80 | private $eTag = ""; 81 | private $size = 0; 82 | private $storageClass = ""; 83 | } -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Model/ObjectListInfo.php: -------------------------------------------------------------------------------- 1 | bucketName = $bucketName; 30 | $this->prefix = $prefix; 31 | $this->marker = $marker; 32 | $this->nextMarker = $nextMarker; 33 | $this->maxKeys = $maxKeys; 34 | $this->isTruncated = $isTruncated; 35 | $this->objectList = $objectList; 36 | $this->commonPrefixes = $commonPrefixes; 37 | } 38 | 39 | /** 40 | * @return the $commonPrefixes 41 | */ 42 | public function getCommonPrefixes() 43 | { 44 | return $this->commonPrefixes; 45 | } 46 | 47 | /** 48 | * @param Ambigous $commonPrefixes 49 | */ 50 | public function setCommonPrefixes($commonPrefixes) 51 | { 52 | $this->commonPrefixes = $commonPrefixes; 53 | } 54 | 55 | /** 56 | * @return string 57 | */ 58 | public function getBucketName() 59 | { 60 | return $this->bucketName; 61 | } 62 | 63 | /** 64 | * @return string 65 | */ 66 | public function getPrefix() 67 | { 68 | return $this->prefix; 69 | } 70 | 71 | /** 72 | * @return string 73 | */ 74 | public function getMarker() 75 | { 76 | return $this->marker; 77 | } 78 | 79 | /** 80 | * @return int 81 | */ 82 | public function getMaxKeys() 83 | { 84 | return $this->maxKeys; 85 | } 86 | 87 | 88 | /** 89 | * @return mixed 90 | */ 91 | public function getIsTruncated() 92 | { 93 | return $this->isTruncated; 94 | } 95 | 96 | /** 97 | * 返回ListObjects接口返回数据中的ObjectInfo列表 98 | * 99 | * @return ObjectInfo[] 100 | */ 101 | public function getObjectList() 102 | { 103 | return $this->objectList; 104 | } 105 | 106 | /** 107 | * @return string 108 | */ 109 | public function getNextMarker() 110 | { 111 | return $this->nextMarker; 112 | } 113 | 114 | private $bucketName = ''; 115 | private $prefix = ''; 116 | private $marker = ''; 117 | private $nextMarker = ''; 118 | private $maxKeys = 0; 119 | private $isTruncated = null; 120 | private $objectList = array(); 121 | private $commonPrefixes = ''; 122 | } -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Model/PartInfo.php: -------------------------------------------------------------------------------- 1 | partNumber = $partNumber; 10 | $this->lastModified = $lastModified; 11 | $this->eTag = $eTag; 12 | $this->size = $size; 13 | } 14 | 15 | /** 16 | * @return the $partNumber 17 | */ 18 | public function getPartNumber() 19 | { 20 | return $this->partNumber; 21 | } 22 | 23 | /** 24 | * @return the $lastModified 25 | */ 26 | public function getLastModified() 27 | { 28 | return $this->lastModified; 29 | } 30 | 31 | /** 32 | * @return the $eTag 33 | */ 34 | public function getETag() 35 | { 36 | return $this->eTag; 37 | } 38 | 39 | /** 40 | * @return the $size 41 | */ 42 | public function getSize() 43 | { 44 | return $this->size; 45 | } 46 | 47 | private $partNumber = 0; 48 | private $lastModified =''; 49 | private $eTag = ''; 50 | private $size = 0; 51 | } 52 | 53 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Model/UploadInfo.php: -------------------------------------------------------------------------------- 1 | key = $key; 10 | $this->uploadId = $uploadId; 11 | $this->storageClass = $storageClass; 12 | } 13 | 14 | /** 15 | * @return the $bucket 16 | */ 17 | public function getKey() 18 | { 19 | return $this->key; 20 | } 21 | 22 | /** 23 | * @return the $uploadId 24 | */ 25 | public function getUploadId() 26 | { 27 | return $this->uploadId; 28 | } 29 | 30 | /** 31 | * @return the $storageClass 32 | */ 33 | public function getStorageClass() 34 | { 35 | return $this->storageClass; 36 | } 37 | 38 | 39 | private $key = ''; 40 | private $uploadId = ''; 41 | private $storageClass =''; 42 | } 43 | 44 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Model/XmlConfig.php: -------------------------------------------------------------------------------- 1 | rawResponse->body) ? "" : $this->rawResponse->body; 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/ExistResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->status) === 200 ? true : false; 18 | } 19 | 20 | /** 21 | * 根据返回http状态码判断,[200-299]即认为是OK, 判断是否存在的接口,404也认为是一种 22 | * 有效响应 23 | * 24 | * @return bool 25 | */ 26 | protected function isResponseOk() 27 | { 28 | $status = $this->rawResponse->status; 29 | if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) { 30 | return true; 31 | } 32 | return false; 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/GetLocationResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->body; 12 | if (!isset($content) || empty($content)) { 13 | throw new NosException("invalid response,empty response body"); 14 | } 15 | try { 16 | $xml = simplexml_load_string($content); 17 | } catch (\Exception $e) { 18 | throw new NosException("invalid response,response body is invalid xml"); 19 | } 20 | $location = strval($xml['0']); 21 | if ($xml->count() != 0) { 22 | throw new NosException("invalid response,child found,xml format exception"); 23 | } 24 | return $location; 25 | } 26 | } 27 | 28 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/GetObjectMetaResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->header; 10 | } 11 | } 12 | 13 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/InitiateMultipartUploadResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->body; 12 | if (! isset($content) || empty($content)) { 13 | throw new NosException("invalid response,empty response body"); 14 | } 15 | try { 16 | $xml = simplexml_load_string($content); 17 | } catch (\Exception $e) { 18 | throw new NosException("invalid response,response body is invalid xml"); 19 | } 20 | if (isset($xml->UploadId)) { 21 | return strval($xml->UploadId); 22 | } 23 | throw new NosException("invalid response,no UploadId found,xml format exception"); 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/ListBucketsResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->body; 24 | if (! isset($content) || empty($content)) { 25 | throw new NosException("invalid response,empty response body"); 26 | } 27 | try { 28 | $xml = new \SimpleXMLElement($content); 29 | } catch (\Exception $e) { 30 | throw new NosException("invalid response,response body is invalid xml"); 31 | } 32 | if (isset($xml->Buckets) && isset($xml->Buckets->Bucket)) { 33 | foreach ($xml->Buckets->Bucket as $bucket) { 34 | $bucketInfo = new BucketInfo(strval($bucket->Name), strval($bucket->CreationDate)); 35 | $bucketList[] = $bucketInfo; 36 | } 37 | } 38 | return new BucketListInfo($bucketList); 39 | } 40 | } -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/ListMultipartUploadResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->body; 14 | if (! isset($content) || empty($content)) { 15 | throw new NosException("invalid response,empty response body"); 16 | } 17 | try { 18 | $xml = simplexml_load_string($content); 19 | } catch (\Exception $e) { 20 | throw new NosException("invalid response,response body is invalid xml"); 21 | } 22 | 23 | $bucket = isset($xml->Bucket) ? strval($xml->Bucket) : ""; 24 | $nextKeyMarker = isset($xml->NextKeyMarker) ? strval($xml->NextKeyMarker) : ""; 25 | $isTruncated = isset($xml->IsTruncated)? strval($xml->IsTruncated):''; 26 | $listUpload = array(); 27 | 28 | if (isset($xml->Upload)) { 29 | foreach ($xml->Upload as $upload) { 30 | $key = isset($upload->Key) ? strval($upload->Key) : ""; 31 | $uploadId = isset($upload->UploadId) ? strval($upload->UploadId) : ""; 32 | $storageClass = isset($upload->StorageClass) ? strval($upload->StorageClass) : ""; 33 | $listUpload[] = new UploadInfo($key, $uploadId, $storageClass); 34 | } 35 | } 36 | return new ListMultipartUploadInfo($bucket, $nextKeyMarker,$isTruncated, $listUpload); 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/ListObjectsResult.php: -------------------------------------------------------------------------------- 1 | Contents)) { 20 | foreach ($xml->Contents as $content) { 21 | $key = isset($content->Key) ? strval($content->Key) : ''; 22 | $lastModified = isset($content->LastModified) ? strval($content->LastModified) : ''; 23 | $eTag = isset($content->ETag) ? strval($content->ETag) : ''; 24 | $size = isset($content->Size) ? intval($content->Size) : 0; 25 | $storageClass = isset($content->StorageClass) ? strval($content->StorageClass) : ""; 26 | $objectList[] = new ObjectInfo($key, $lastModified, $eTag, $size, $storageClass); 27 | } 28 | } 29 | return $objectList; 30 | } 31 | 32 | /** 33 | * 解析ListObjects接口返回的xml数据 34 | * 35 | * return ObjectListInfo 36 | */ 37 | protected function parseDataFromResponse() 38 | { 39 | $content = $this->rawResponse->body; 40 | if(!isset($content) || empty($content)) 41 | { 42 | throw new NosException("invalid response,empty response body"); 43 | } 44 | try { 45 | $xml = new \SimpleXMLElement($this->rawResponse->body); 46 | } catch (\Exception $e) { 47 | throw new NosException("invalid response,response body invalid xml"); 48 | } 49 | $bucketName = isset($xml->Name) ? strval($xml->Name) : ''; 50 | $prfix = isset($xml->Prefix) ? strval($xml->Prefix) : ''; 51 | $maxKeys = isset($xml->MaxKeys) ? intval($xml->MaxKeys) : ''; 52 | $marker = isset($xml->Marker) ? strval($xml->Marker) : ''; 53 | $nextMarker = isset($xml->NextMarker) ? strval($xml->NextMarker) : ''; 54 | $isTruncatedStr = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : ''; 55 | $isTruncated = $isTruncatedStr === "true" ? true : false; 56 | $commonPrefixes = isset($xml->CommonPrefixes) ? strval($xml->CommonPrefixes->Prefix) : ''; 57 | $objectList = $this->parseObjectList($xml); 58 | return new ObjectListInfo($bucketName, $prfix, $commonPrefixes, $marker, $nextMarker, $maxKeys, $isTruncated, $objectList); 59 | } 60 | } -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/ListPartsResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->body; 14 | if (! isset($content) || empty($content)) { 15 | throw new NosException("invalid response,empty response body"); 16 | } 17 | try { 18 | $xml = simplexml_load_string($content); 19 | } catch (\Exception $e) { 20 | throw new NosException("invalid response,response body invalid xml"); 21 | } 22 | $bucket = isset($xml->Bucket) ? strval($xml->Bucket) : ''; 23 | $key = isset($xml->Key) ? strval($xml->Key) : ''; 24 | $uploadId = isset($xml->UploadId) ? strval($xml->UploadId) : ''; 25 | $storageClass = isset($xml->StorageClass) ? strval($xml->StorageClass) : ''; 26 | $partNumberMarker = isset($xml->PartNumberMarker) ? intval($xml->PartNumberMarker) : ''; 27 | $nextPartNumberMarker = isset($xml->NextPartNumberMarker) ? intval($xml->NextPartNumberMarker) : ''; 28 | $maxParts = isset($xml->MaxParts) ? intval($xml->MaxParts) : ''; 29 | $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : ''; 30 | $partList = array(); 31 | if (isset($xml->Part)) { 32 | foreach ($xml->Part as $part) { 33 | $partNumber = isset($part->PartNumber) ? intval($part->PartNumber) : ''; 34 | $lastModified = isset($part->LastModified) ? strval($part->LastModified) : ''; 35 | $eTag = isset($part->ETag) ? strval($part->ETag) : ''; 36 | $size = isset($part->Size) ? intval($part->Size) : ''; 37 | $partList[] = new PartInfo($partNumber, $lastModified, $eTag, $size); 38 | } 39 | } 40 | return new ListPartsInfo($bucket, $key, $uploadId, $storageClass, $partNumberMarker, $nextPartNumberMarker, $maxParts, $isTruncated, $partList); 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/MultiDeleteResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->body; 13 | if (! isset($content) || empty($content)) { 14 | throw new NosException("invalid response,empty response body"); 15 | } 16 | try { 17 | $xml = simplexml_load_string($content); 18 | } catch (\Exception $e) { 19 | throw new NosException("invalid response,response body invalid xml"); 20 | } 21 | if(!isset($xml->Error) && !isset($xml->Deleted)){ 22 | return null; 23 | } 24 | $succ = array(); 25 | foreach ($xml->Deleted as $deleted){ 26 | $succ[] = strval($deleted->Key); 27 | } 28 | $fails = array(); 29 | foreach ($xml->Error as $err){ 30 | $failInfo = new DeleteFailedInfo(strval($err->Key),strval($err->Code),strval($err->Message)); 31 | $fails[] = $failInfo; 32 | } 33 | $result = array(); 34 | if(count($succ)){ 35 | $result['succeed'] = $succ; 36 | } 37 | if(count($fails)){ 38 | $result['failed'] = $fails; 39 | } 40 | return $result; 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/ObjDeduplicateResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->body; 11 | if(!isset($content) || empty($content)) 12 | { 13 | throw new NosException("invalid response,empty rsoponse body"); 14 | } 15 | try { 16 | $xml = simplexml_load_string($content); 17 | }catch(\Exception $e) 18 | { 19 | throw new NosException("invalid response,rsoponse body is invalid xml"); 20 | } 21 | if(isset($xml->ObjectContentAlreadyExist)) 22 | { 23 | return strval($xml->ObjectContentAlreadyExist); 24 | } 25 | throw new NosException("invalid response,no ObjectContentAlreadyExist found,xml format exception"); 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/PutSetDeleteResult.php: -------------------------------------------------------------------------------- 1 | rawResponse = $response; 28 | $this->parseResponse(); 29 | } 30 | 31 | /** 32 | * 获取requestId 33 | * 34 | * @return string 35 | */ 36 | public function getRequestId() 37 | { 38 | if (isset($this->rawResponse) && 39 | isset($this->rawResponse->header) && 40 | isset($this->rawResponse->header['x-nos-request-id']) 41 | ) { 42 | return $this->rawResponse->header['x-nos-request-id']; 43 | } else { 44 | return ''; 45 | } 46 | } 47 | 48 | /** 49 | * 得到返回数据,不同的请求返回数据格式不同 50 | * 51 | * $return mixed 52 | */ 53 | public function getData() 54 | { 55 | return $this->parsedData; 56 | } 57 | 58 | /** 59 | * 由子类实现,不同的请求返回数据有不同的解析逻辑,由子类实现 60 | * 61 | * @return mixed 62 | */ 63 | abstract protected function parseDataFromResponse(); 64 | 65 | /** 66 | * 操作是否成功 67 | * 68 | * @return mixed 69 | */ 70 | public function isOK() 71 | { 72 | return $this->isOk; 73 | } 74 | 75 | /** 76 | * @throws NOSException 77 | */ 78 | public function parseResponse() 79 | { 80 | $this->isOk = $this->isResponseOk(); 81 | if ($this->isOk) { 82 | $this->parsedData = $this->parseDataFromResponse(); 83 | } else { 84 | $httpStatus = strval($this->rawResponse->status); 85 | $requestId = strval($this->getRequestId()); 86 | $code = $this->retrieveErrorCode($this->rawResponse->body); 87 | $message = $this->retrieveErrorMessage($this->rawResponse->body); 88 | $body = $this->rawResponse->body; 89 | 90 | $details = array( 91 | 'status' => $httpStatus, 92 | 'request-id' => $requestId, 93 | 'code' => $code, 94 | 'message' => $message, 95 | 'body' => $body 96 | ); 97 | throw new NosException($details); 98 | } 99 | } 100 | 101 | /** 102 | * 尝试从body中获取错误Message 103 | * 104 | * @param $body 105 | * @return string 106 | */ 107 | private function retrieveErrorMessage($body) 108 | { 109 | if (empty($body) || false === strpos($body, 'Message)) { 114 | return strval($xml->Message); 115 | } 116 | return ''; 117 | } 118 | 119 | /** 120 | * 尝试从body中获取错误Code 121 | * 122 | * @param $body 123 | * @return string 124 | */ 125 | private function retrieveErrorCode($body) 126 | { 127 | if (empty($body) || false === strpos($body, 'Code)) { 132 | return strval($xml->Code); 133 | } 134 | return ''; 135 | } 136 | 137 | /** 138 | * 根据返回http状态码判断,[200-299]即认为是OK 139 | * 140 | * @return bool 141 | */ 142 | protected function isResponseOk() 143 | { 144 | $status = $this->rawResponse->status; 145 | if ((int)(intval($status) / 100) == 2) { 146 | return true; 147 | } 148 | return false; 149 | } 150 | 151 | /** 152 | * 返回原始的返回数据 153 | * 154 | * @return ResponseCore 155 | */ 156 | public function getRawResponse() 157 | { 158 | return $this->rawResponse; 159 | } 160 | 161 | /** 162 | * 标示请求是否成功 163 | */ 164 | protected $isOk = false; 165 | /** 166 | * 由子类解析过的数据 167 | */ 168 | protected $parsedData = null; 169 | /** 170 | * 存放auth函数返回的原始Response 171 | * 172 | * @var ResponseCore 173 | */ 174 | protected $rawResponse; 175 | } 176 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/UploadPartResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->header; 10 | if (isset($header["etag"])) { 11 | return trim($header["etag"],"\""); 12 | } 13 | throw new NosException("cannot get ETag"); 14 | } 15 | } 16 | 17 | -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/aclResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->header['x-nos-acl'])) 16 | { 17 | $acl_type = strval($this->rawResponse->header['x-nos-acl']); 18 | return $acl_type; 19 | } 20 | else 21 | { 22 | throw new NosException("invalid response,no require head found"); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /cloud/nos/src/NOS/Result/statusResult.php: -------------------------------------------------------------------------------- 1 | rawResponse->body; 12 | if(empty($content)) 13 | { 14 | throw new NosException("invalid response,,empty response body"); 15 | } 16 | try { 17 | $xml = simplexml_load_string($content); 18 | }catch(\Exception $e) 19 | { 20 | throw new NosException("invalid response,,response body is invalid xml"); 21 | } 22 | if(isset($xml->Status)) 23 | { 24 | return strval($xml->Status); 25 | } 26 | else 27 | { 28 | throw new NosException("invalid response,no Status found,xml format exception"); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /cloud/qiniu/autoload.php: -------------------------------------------------------------------------------- 1 | accessKey = $accessKey; 14 | $this->secretKey = $secretKey; 15 | } 16 | 17 | public function getAccessKey() 18 | { 19 | return $this->accessKey; 20 | } 21 | 22 | public function sign($data) 23 | { 24 | $hmac = hash_hmac('sha1', $data, $this->secretKey, true); 25 | return $this->accessKey . ':' . \Qiniu\base64_urlSafeEncode($hmac); 26 | } 27 | 28 | public function signWithData($data) 29 | { 30 | $encodedData = \Qiniu\base64_urlSafeEncode($data); 31 | return $this->sign($encodedData) . ':' . $encodedData; 32 | } 33 | 34 | public function signRequest($urlString, $body, $contentType = null) 35 | { 36 | $url = parse_url($urlString); 37 | $data = ''; 38 | if (array_key_exists('path', $url)) { 39 | $data = $url['path']; 40 | } 41 | if (array_key_exists('query', $url)) { 42 | $data .= '?' . $url['query']; 43 | } 44 | $data .= "\n"; 45 | 46 | if ($body !== null && $contentType === 'application/x-www-form-urlencoded') { 47 | $data .= $body; 48 | } 49 | return $this->sign($data); 50 | } 51 | 52 | public function verifyCallback($contentType, $originAuthorization, $url, $body) 53 | { 54 | $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType); 55 | return $originAuthorization === $authorization; 56 | } 57 | 58 | public function privateDownloadUrl($baseUrl, $expires = 3600) 59 | { 60 | $deadline = time() + $expires; 61 | 62 | $pos = strpos($baseUrl, '?'); 63 | if ($pos !== false) { 64 | $baseUrl .= '&e='; 65 | } else { 66 | $baseUrl .= '?e='; 67 | } 68 | $baseUrl .= $deadline; 69 | 70 | $token = $this->sign($baseUrl); 71 | return "$baseUrl&token=$token"; 72 | } 73 | 74 | public function uploadToken($bucket, $key = null, $expires = 3600, $policy = null, $strictPolicy = true) 75 | { 76 | $deadline = time() + $expires; 77 | $scope = $bucket; 78 | if ($key !== null) { 79 | $scope .= ':' . $key; 80 | } 81 | 82 | $args = self::copyPolicy($args, $policy, $strictPolicy); 83 | $args['scope'] = $scope; 84 | $args['deadline'] = $deadline; 85 | 86 | $b = json_encode($args); 87 | return $this->signWithData($b); 88 | } 89 | 90 | /** 91 | *上传策略,参数规格详见 92 | *http://developer.qiniu.com/docs/v6/api/reference/security/put-policy.html 93 | */ 94 | private static $policyFields = array( 95 | 'callbackUrl', 96 | 'callbackBody', 97 | 'callbackHost', 98 | 'callbackBodyType', 99 | 'callbackFetchKey', 100 | 101 | 'returnUrl', 102 | 'returnBody', 103 | 104 | 'endUser', 105 | 'saveKey', 106 | 'insertOnly', 107 | 108 | 'detectMime', 109 | 'mimeLimit', 110 | 'fsizeMin', 111 | 'fsizeLimit', 112 | 113 | 'persistentOps', 114 | 'persistentNotifyUrl', 115 | 'persistentPipeline', 116 | 117 | 'deleteAfterDays', 118 | 'fileType', 119 | 'isPrefixalScope', 120 | ); 121 | 122 | private static function copyPolicy(&$policy, $originPolicy, $strictPolicy) 123 | { 124 | if ($originPolicy === null) { 125 | return array(); 126 | } 127 | foreach ($originPolicy as $key => $value) { 128 | if (!$strictPolicy || in_array((string)$key, self::$policyFields, true)) { 129 | $policy[$key] = $value; 130 | } 131 | } 132 | return $policy; 133 | } 134 | 135 | public function authorization($url, $body = null, $contentType = null) 136 | { 137 | $authorization = 'QBox ' . $this->signRequest($url, $body, $contentType); 138 | return array('Authorization' => $authorization); 139 | } 140 | 141 | public function authorizationV2($url, $method, $body = null, $contentType = null) 142 | { 143 | $urlItems = parse_url($url); 144 | $host = $urlItems['host']; 145 | 146 | if (isset($urlItems['port'])) { 147 | $port = $urlItems['port']; 148 | } else { 149 | $port = ''; 150 | } 151 | 152 | $path = $urlItems['path']; 153 | if (isset($urlItems['query'])) { 154 | $query = $urlItems['query']; 155 | } else { 156 | $query = ''; 157 | } 158 | 159 | //write request uri 160 | $toSignStr = $method . ' ' . $path; 161 | if (!empty($query)) { 162 | $toSignStr .= '?' . $query; 163 | } 164 | 165 | //write host and port 166 | $toSignStr .= "\nHost: " . $host; 167 | if (!empty($port)) { 168 | $toSignStr .= ":" . $port; 169 | } 170 | 171 | //write content type 172 | if (!empty($contentType)) { 173 | $toSignStr .= "\nContent-Type: " . $contentType; 174 | } 175 | 176 | $toSignStr .= "\n\n"; 177 | 178 | //write body 179 | if (!empty($body)) { 180 | $toSignStr .= $body; 181 | } 182 | 183 | $sign = $this->sign($toSignStr); 184 | $auth = 'Qiniu ' . $sign; 185 | return array('Authorization' => $auth); 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Config.php: -------------------------------------------------------------------------------- 1 | zone = $z; 30 | $this->useHTTPS = false; 31 | $this->useCdnDomains = false; 32 | $this->zoneCache = array(); 33 | } 34 | 35 | public function getUpHost($accessKey, $bucket) 36 | { 37 | $zone = $this->getZone($accessKey, $bucket); 38 | if ($this->useHTTPS === true) { 39 | $scheme = "https://"; 40 | } else { 41 | $scheme = "http://"; 42 | } 43 | 44 | $host = $zone->srcUpHosts[0]; 45 | if ($this->useCdnDomains === true) { 46 | $host = $zone->cdnUpHosts[0]; 47 | } 48 | 49 | return $scheme . $host; 50 | } 51 | 52 | public function getUpBackupHost($accessKey, $bucket) 53 | { 54 | $zone = $this->getZone($accessKey, $bucket); 55 | if ($this->useHTTPS === true) { 56 | $scheme = "https://"; 57 | } else { 58 | $scheme = "http://"; 59 | } 60 | 61 | $host = $zone->cdnUpHosts[0]; 62 | if ($this->useCdnDomains === true) { 63 | $host = $zone->srcUpHosts[0]; 64 | } 65 | 66 | return $scheme . $host; 67 | } 68 | 69 | public function getRsHost($accessKey, $bucket) 70 | { 71 | $zone = $this->getZone($accessKey, $bucket); 72 | 73 | if ($this->useHTTPS === true) { 74 | $scheme = "https://"; 75 | } else { 76 | $scheme = "http://"; 77 | } 78 | 79 | return $scheme . $zone->rsHost; 80 | } 81 | 82 | public function getRsfHost($accessKey, $bucket) 83 | { 84 | $zone = $this->getZone($accessKey, $bucket); 85 | 86 | if ($this->useHTTPS === true) { 87 | $scheme = "https://"; 88 | } else { 89 | $scheme = "http://"; 90 | } 91 | 92 | return $scheme . $zone->rsfHost; 93 | } 94 | 95 | public function getIovipHost($accessKey, $bucket) 96 | { 97 | $zone = $this->getZone($accessKey, $bucket); 98 | 99 | if ($this->useHTTPS === true) { 100 | $scheme = "https://"; 101 | } else { 102 | $scheme = "http://"; 103 | } 104 | 105 | return $scheme . $zone->iovipHost; 106 | } 107 | 108 | public function getApiHost($accessKey, $bucket) 109 | { 110 | $zone = $this->getZone($accessKey, $bucket); 111 | 112 | if ($this->useHTTPS === true) { 113 | $scheme = "https://"; 114 | } else { 115 | $scheme = "http://"; 116 | } 117 | 118 | return $scheme . $zone->apiHost; 119 | } 120 | 121 | private function getZone($accessKey, $bucket) 122 | { 123 | $cacheId = "$accessKey:$bucket"; 124 | 125 | if (isset($this->zoneCache[$cacheId])) { 126 | $zone = $this->zoneCache[$cacheId]; 127 | } elseif (isset($this->zone)) { 128 | $zone = $this->zone; 129 | $this->zoneCache[$cacheId] = $zone; 130 | } else { 131 | $zone = Zone::queryZone($accessKey, $bucket); 132 | $this->zoneCache[$cacheId] = $zone; 133 | } 134 | return $zone; 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Etag.php: -------------------------------------------------------------------------------- 1 | $val) { 41 | array_push($data, '--' . $mimeBoundary); 42 | array_push($data, "Content-Disposition: form-data; name=\"$key\""); 43 | array_push($data, ''); 44 | array_push($data, $val); 45 | } 46 | 47 | array_push($data, '--' . $mimeBoundary); 48 | $finalMimeType = empty($mimeType) ? 'application/octet-stream' : $mimeType; 49 | $finalFileName = self::escapeQuotes($fileName); 50 | array_push($data, "Content-Disposition: form-data; name=\"$name\"; filename=\"$finalFileName\""); 51 | array_push($data, "Content-Type: $finalMimeType"); 52 | array_push($data, ''); 53 | array_push($data, $fileBody); 54 | 55 | array_push($data, '--' . $mimeBoundary . '--'); 56 | array_push($data, ''); 57 | 58 | $body = implode("\r\n", $data); 59 | $contentType = 'multipart/form-data; boundary=' . $mimeBoundary; 60 | $headers['Content-Type'] = $contentType; 61 | $request = new Request('POST', $url, $headers, $body); 62 | return self::sendRequest($request); 63 | } 64 | 65 | private static function userAgent() 66 | { 67 | $sdkInfo = "QiniuPHP/" . Config::SDK_VER; 68 | 69 | $systemInfo = php_uname("s"); 70 | $machineInfo = php_uname("m"); 71 | 72 | $envInfo = "($systemInfo/$machineInfo)"; 73 | 74 | $phpVer = phpversion(); 75 | 76 | $ua = "$sdkInfo $envInfo PHP/$phpVer"; 77 | return $ua; 78 | } 79 | 80 | public static function sendRequest($request) 81 | { 82 | $t1 = microtime(true); 83 | $ch = curl_init(); 84 | $options = array( 85 | CURLOPT_USERAGENT => self::userAgent(), 86 | CURLOPT_RETURNTRANSFER => true, 87 | CURLOPT_SSL_VERIFYPEER => false, 88 | CURLOPT_SSL_VERIFYHOST => false, 89 | CURLOPT_HEADER => true, 90 | CURLOPT_NOBODY => false, 91 | CURLOPT_CUSTOMREQUEST => $request->method, 92 | CURLOPT_URL => $request->url, 93 | ); 94 | 95 | // Handle open_basedir & safe mode 96 | if (!ini_get('safe_mode') && !ini_get('open_basedir')) { 97 | $options[CURLOPT_FOLLOWLOCATION] = true; 98 | } 99 | 100 | if (!empty($request->headers)) { 101 | $headers = array(); 102 | foreach ($request->headers as $key => $val) { 103 | array_push($headers, "$key: $val"); 104 | } 105 | $options[CURLOPT_HTTPHEADER] = $headers; 106 | } 107 | curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:')); 108 | 109 | if (!empty($request->body)) { 110 | $options[CURLOPT_POSTFIELDS] = $request->body; 111 | } 112 | curl_setopt_array($ch, $options); 113 | $result = curl_exec($ch); 114 | $t2 = microtime(true); 115 | $duration = round($t2 - $t1, 3); 116 | $ret = curl_errno($ch); 117 | if ($ret !== 0) { 118 | $r = new Response(-1, $duration, array(), null, curl_error($ch)); 119 | curl_close($ch); 120 | return $r; 121 | } 122 | $code = curl_getinfo($ch, CURLINFO_HTTP_CODE); 123 | $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); 124 | $headers = self::parseHeaders(substr($result, 0, $header_size)); 125 | $body = substr($result, $header_size); 126 | curl_close($ch); 127 | return new Response($code, $duration, $headers, $body, null); 128 | } 129 | 130 | private static function parseHeaders($raw) 131 | { 132 | $headers = array(); 133 | $headerLines = explode("\r\n", $raw); 134 | foreach ($headerLines as $line) { 135 | $headerLine = trim($line); 136 | $kv = explode(':', $headerLine); 137 | if (count($kv) > 1) { 138 | $kv[0] =self::ucwordsHyphen($kv[0]); 139 | $headers[$kv[0]] = trim($kv[1]); 140 | } 141 | } 142 | return $headers; 143 | } 144 | 145 | private static function escapeQuotes($str) 146 | { 147 | $find = array("\\", "\""); 148 | $replace = array("\\\\", "\\\""); 149 | return str_replace($find, $replace, $str); 150 | } 151 | 152 | private static function ucwordsHyphen($str) 153 | { 154 | return str_replace('- ', '-', ucwords(str_replace('-', '- ', $str))); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Http/Error.php: -------------------------------------------------------------------------------- 1 | 7 | * {"error" : "detailed error message"} 8 | * 9 | */ 10 | final class Error 11 | { 12 | private $url; 13 | private $response; 14 | 15 | public function __construct($url, $response) 16 | { 17 | $this->url = $url; 18 | $this->response = $response; 19 | } 20 | 21 | public function code() 22 | { 23 | return $this->response->statusCode; 24 | } 25 | 26 | public function getResponse() 27 | { 28 | return $this->response; 29 | } 30 | 31 | public function message() 32 | { 33 | return $this->response->error; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Http/Request.php: -------------------------------------------------------------------------------- 1 | method = strtoupper($method); 14 | $this->url = $url; 15 | $this->headers = $headers; 16 | $this->body = $body; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Http/Response.php: -------------------------------------------------------------------------------- 1 | 'Continue', 20 | 101 => 'Switching Protocols', 21 | 102 => 'Processing', 22 | 200 => 'OK', 23 | 201 => 'Created', 24 | 202 => 'Accepted', 25 | 203 => 'Non-Authoritative Information', 26 | 204 => 'No Content', 27 | 205 => 'Reset Content', 28 | 206 => 'Partial Content', 29 | 207 => 'Multi-Status', 30 | 208 => 'Already Reported', 31 | 226 => 'IM Used', 32 | 300 => 'Multiple Choices', 33 | 301 => 'Moved Permanently', 34 | 302 => 'Found', 35 | 303 => 'See Other', 36 | 304 => 'Not Modified', 37 | 305 => 'Use Proxy', 38 | 307 => 'Temporary Redirect', 39 | 308 => 'Permanent Redirect', 40 | 400 => 'Bad Request', 41 | 401 => 'Unauthorized', 42 | 402 => 'Payment Required', 43 | 403 => 'Forbidden', 44 | 404 => 'Not Found', 45 | 405 => 'Method Not Allowed', 46 | 406 => 'Not Acceptable', 47 | 407 => 'Proxy Authentication Required', 48 | 408 => 'Request Timeout', 49 | 409 => 'Conflict', 50 | 410 => 'Gone', 51 | 411 => 'Length Required', 52 | 412 => 'Precondition Failed', 53 | 413 => 'Request Entity Too Large', 54 | 414 => 'Request-URI Too Long', 55 | 415 => 'Unsupported Media Type', 56 | 416 => 'Requested Range Not Satisfiable', 57 | 417 => 'Expectation Failed', 58 | 422 => 'Unprocessable Entity', 59 | 423 => 'Locked', 60 | 424 => 'Failed Dependency', 61 | 425 => 'Reserved for WebDAV advanced collections expired proposal', 62 | 426 => 'Upgrade required', 63 | 428 => 'Precondition Required', 64 | 429 => 'Too Many Requests', 65 | 431 => 'Request Header Fields Too Large', 66 | 500 => 'Internal Server Error', 67 | 501 => 'Not Implemented', 68 | 502 => 'Bad Gateway', 69 | 503 => 'Service Unavailable', 70 | 504 => 'Gateway Timeout', 71 | 505 => 'HTTP Version Not Supported', 72 | 506 => 'Variant Also Negotiates (Experimental)', 73 | 507 => 'Insufficient Storage', 74 | 508 => 'Loop Detected', 75 | 510 => 'Not Extended', 76 | 511 => 'Network Authentication Required', 77 | ); 78 | 79 | /** 80 | * @param int $code 状态码 81 | * @param double $duration 请求时长 82 | * @param array $headers 响应头部 83 | * @param string $body 响应内容 84 | * @param string $error 错误描述 85 | */ 86 | public function __construct($code, $duration, array $headers = array(), $body = null, $error = null) 87 | { 88 | $this->statusCode = $code; 89 | $this->duration = $duration; 90 | $this->headers = $headers; 91 | $this->body = $body; 92 | $this->error = $error; 93 | $this->jsonData = null; 94 | if ($error !== null) { 95 | return; 96 | } 97 | 98 | if ($body === null) { 99 | if ($code >= 400) { 100 | $this->error = self::$statusTexts[$code]; 101 | } 102 | return; 103 | } 104 | if (self::isJson($headers)) { 105 | try { 106 | $jsonData = self::bodyJson($body); 107 | if ($code >= 400) { 108 | $this->error = $body; 109 | if ($jsonData['error'] !== null) { 110 | $this->error = $jsonData['error']; 111 | } 112 | } 113 | $this->jsonData = $jsonData; 114 | } catch (\InvalidArgumentException $e) { 115 | $this->error = $body; 116 | if ($code >= 200 && $code < 300) { 117 | $this->error = $e->getMessage(); 118 | } 119 | } 120 | } elseif ($code >= 400) { 121 | $this->error = $body; 122 | } 123 | return; 124 | } 125 | 126 | public function json() 127 | { 128 | return $this->jsonData; 129 | } 130 | 131 | private static function bodyJson($body) 132 | { 133 | return \Qiniu\json_decode((string) $body, true, 512); 134 | } 135 | 136 | public function xVia() 137 | { 138 | $via = $this->headers['X-Via']; 139 | if ($via === null) { 140 | $via = $this->headers['X-Px']; 141 | } 142 | if ($via === null) { 143 | $via = $this->headers['Fw-Via']; 144 | } 145 | return $via; 146 | } 147 | 148 | public function xLog() 149 | { 150 | return $this->headers['X-Log']; 151 | } 152 | 153 | public function xReqId() 154 | { 155 | return $this->headers['X-Reqid']; 156 | } 157 | 158 | public function ok() 159 | { 160 | return $this->statusCode >= 200 && $this->statusCode < 300 && $this->error === null; 161 | } 162 | 163 | public function needRetry() 164 | { 165 | $code = $this->statusCode; 166 | if ($code < 0 || ($code / 100 === 5 and $code !== 579) || $code === 996) { 167 | return true; 168 | } 169 | } 170 | 171 | private static function isJson($headers) 172 | { 173 | return array_key_exists('Content-Type', $headers) && 174 | strpos($headers['Content-Type'], 'application/json') === 0; 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Processing/ImageUrlBuilder.php: -------------------------------------------------------------------------------- 1 | 49 | */ 50 | public function thumbnail( 51 | $url, 52 | $mode, 53 | $width, 54 | $height, 55 | $format = null, 56 | $interlace = null, 57 | $quality = null, 58 | $ignoreError = 1 59 | ) { 60 | 61 | // url合法效验 62 | if (!$this->isUrl($url)) { 63 | return $url; 64 | } 65 | 66 | // 参数合法性效验 67 | if (!in_array(intval($mode), $this->modeArr, true)) { 68 | return $url; 69 | } 70 | 71 | if (!$width || !$height) { 72 | return $url; 73 | } 74 | 75 | $thumbStr = 'imageView2/' . $mode . '/w/' . $width . '/h/' . $height . '/'; 76 | 77 | // 拼接输出格式 78 | if (!is_null($format) 79 | && in_array($format, $this->formatArr) 80 | ) { 81 | $thumbStr .= 'format/' . $format . '/'; 82 | } 83 | 84 | // 拼接渐进显示 85 | if (!is_null($interlace) 86 | && in_array(intval($interlace), array(0, 1), true) 87 | ) { 88 | $thumbStr .= 'interlace/' . $interlace . '/'; 89 | } 90 | 91 | // 拼接图片质量 92 | if (!is_null($quality) 93 | && intval($quality) >= 0 94 | && intval($quality) <= 100 95 | ) { 96 | $thumbStr .= 'q/' . $quality . '/'; 97 | } 98 | 99 | $thumbStr .= 'ignore-error/' . $ignoreError . '/'; 100 | 101 | // 如果有query_string用|线分割实现多参数 102 | return $url . ($this->hasQuery($url) ? '|' : '?') . $thumbStr; 103 | } 104 | 105 | /** 106 | * 图片水印 107 | * 108 | * @param string $url 图片链接 109 | * @param string $image 水印图片链接 110 | * @param numeric $dissolve 透明度 111 | * @param string $gravity 水印位置 112 | * @param numeric $dx 横轴边距 113 | * @param numeric $dy 纵轴边距 114 | * @param numeric $watermarkScale 自适应原图的短边比例 115 | * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html 116 | * @return string 117 | * @author Sherlock Ren 118 | */ 119 | public function waterImg( 120 | $url, 121 | $image, 122 | $dissolve = 100, 123 | $gravity = 'SouthEast', 124 | $dx = null, 125 | $dy = null, 126 | $watermarkScale = null 127 | ) { 128 | // url合法效验 129 | if (!$this->isUrl($url)) { 130 | return $url; 131 | } 132 | 133 | $waterStr = 'watermark/1/image/' . \Qiniu\base64_urlSafeEncode($image) . '/'; 134 | 135 | // 拼接水印透明度 136 | if (is_numeric($dissolve) 137 | && $dissolve <= 100 138 | ) { 139 | $waterStr .= 'dissolve/' . $dissolve . '/'; 140 | } 141 | 142 | // 拼接水印位置 143 | if (in_array($gravity, $this->gravityArr, true)) { 144 | $waterStr .= 'gravity/' . $gravity . '/'; 145 | } 146 | 147 | // 拼接横轴边距 148 | if (!is_null($dx) 149 | && is_numeric($dx) 150 | ) { 151 | $waterStr .= 'dx/' . $dx . '/'; 152 | } 153 | 154 | // 拼接纵轴边距 155 | if (!is_null($dy) 156 | && is_numeric($dy) 157 | ) { 158 | $waterStr .= 'dy/' . $dy . '/'; 159 | } 160 | 161 | // 拼接自适应原图的短边比例 162 | if (!is_null($watermarkScale) 163 | && is_numeric($watermarkScale) 164 | && $watermarkScale > 0 165 | && $watermarkScale < 1 166 | ) { 167 | $waterStr .= 'ws/' . $watermarkScale . '/'; 168 | } 169 | 170 | // 如果有query_string用|线分割实现多参数 171 | return $url . ($this->hasQuery($url) ? '|' : '?') . $waterStr; 172 | } 173 | 174 | /** 175 | * 文字水印 176 | * 177 | * @param string $url 图片链接 178 | * @param string $text 文字 179 | * @param string $font 文字字体 180 | * @param string $fontSize 文字字号 181 | * @param string $fontColor 文字颜色 182 | * @param numeric $dissolve 透明度 183 | * @param string $gravity 水印位置 184 | * @param numeric $dx 横轴边距 185 | * @param numeric $dy 纵轴边距 186 | * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark 187 | * @return string 188 | * @author Sherlock Ren 189 | */ 190 | public function waterText( 191 | $url, 192 | $text, 193 | $font = '黑体', 194 | $fontSize = 0, 195 | $fontColor = null, 196 | $dissolve = 100, 197 | $gravity = 'SouthEast', 198 | $dx = null, 199 | $dy = null 200 | ) { 201 | // url合法效验 202 | if (!$this->isUrl($url)) { 203 | return $url; 204 | } 205 | 206 | $waterStr = 'watermark/2/text/' 207 | . \Qiniu\base64_urlSafeEncode($text) . '/font/' 208 | . \Qiniu\base64_urlSafeEncode($font) . '/'; 209 | 210 | // 拼接文字大小 211 | if (is_int($fontSize)) { 212 | $waterStr .= 'fontsize/' . $fontSize . '/'; 213 | } 214 | 215 | // 拼接文字颜色 216 | if (!is_null($fontColor) 217 | && $fontColor 218 | ) { 219 | $waterStr .= 'fill/' . \Qiniu\base64_urlSafeEncode($fontColor) . '/'; 220 | } 221 | 222 | // 拼接水印透明度 223 | if (is_numeric($dissolve) 224 | && $dissolve <= 100 225 | ) { 226 | $waterStr .= 'dissolve/' . $dissolve . '/'; 227 | } 228 | 229 | // 拼接水印位置 230 | if (in_array($gravity, $this->gravityArr, true)) { 231 | $waterStr .= 'gravity/' . $gravity . '/'; 232 | } 233 | 234 | // 拼接横轴边距 235 | if (!is_null($dx) 236 | && is_numeric($dx) 237 | ) { 238 | $waterStr .= 'dx/' . $dx . '/'; 239 | } 240 | 241 | // 拼接纵轴边距 242 | if (!is_null($dy) 243 | && is_numeric($dy) 244 | ) { 245 | $waterStr .= 'dy/' . $dy . '/'; 246 | } 247 | 248 | // 如果有query_string用|线分割实现多参数 249 | return $url . ($this->hasQuery($url) ? '|' : '?') . $waterStr; 250 | } 251 | 252 | /** 253 | * 效验url合法性 254 | * 255 | * @param string $url url链接 256 | * @return string 257 | * @author Sherlock Ren 258 | */ 259 | protected function isUrl($url) 260 | { 261 | $urlArr = parse_url($url); 262 | 263 | return $urlArr['scheme'] 264 | && in_array($urlArr['scheme'], array('http', 'https')) 265 | && $urlArr['host'] 266 | && $urlArr['path']; 267 | } 268 | 269 | /** 270 | * 检测是否有query 271 | * 272 | * @param string $url url链接 273 | * @return string 274 | * @author Sherlock Ren 275 | */ 276 | protected function hasQuery($url) 277 | { 278 | $urlArr = parse_url($url); 279 | 280 | return !empty($urlArr['query']); 281 | } 282 | } 283 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Processing/Operation.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 18 | $this->domain = $domain; 19 | $this->token_expire = $token_expire; 20 | } 21 | 22 | 23 | /** 24 | * 对资源文件进行处理 25 | * 26 | * @param $key 待处理的资源文件名 27 | * @param $fops string|array fop操作,多次fop操作以array的形式传入。 28 | * eg. imageView2/1/w/200/h/200, imageMogr2/thumbnail/!75px 29 | * 30 | * @return array 文件处理后的结果及错误。 31 | * 32 | * @link http://developer.qiniu.com/docs/v6/api/reference/fop/ 33 | */ 34 | public function execute($key, $fops) 35 | { 36 | $url = $this->buildUrl($key, $fops); 37 | $resp = Client::get($url); 38 | if (!$resp->ok()) { 39 | return array(null, new Error($url, $resp)); 40 | } 41 | if ($resp->json() !== null) { 42 | return array($resp->json(), null); 43 | } 44 | return array($resp->body, null); 45 | } 46 | 47 | public function buildUrl($key, $fops, $protocol = 'http') 48 | { 49 | if (is_array($fops)) { 50 | $fops = implode('|', $fops); 51 | } 52 | 53 | $url = $protocol . "://$this->domain/$key?$fops"; 54 | if ($this->auth !== null) { 55 | $url = $this->auth->privateDownloadUrl($url, $this->token_expire); 56 | } 57 | 58 | return $url; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Processing/PersistentFop.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 30 | if ($config == null) { 31 | $this->config = new Config(); 32 | } else { 33 | $this->config = $config; 34 | } 35 | } 36 | 37 | /** 38 | * 对资源文件进行异步持久化处理 39 | * @param $bucket 资源所在空间 40 | * @param $key 待处理的源文件 41 | * @param $fops string|array 待处理的pfop操作,多个pfop操作以array的形式传入。 42 | * eg. avthumb/mp3/ab/192k, vframe/jpg/offset/7/w/480/h/360 43 | * @param $pipeline 资源处理队列 44 | * @param $notify_url 处理结果通知地址 45 | * @param $force 是否强制执行一次新的指令 46 | * 47 | * 48 | * @return array 返回持久化处理的persistentId, 和返回的错误。 49 | * 50 | * @link http://developer.qiniu.com/docs/v6/api/reference/fop/ 51 | */ 52 | public function execute($bucket, $key, $fops, $pipeline = null, $notify_url = null, $force = false) 53 | { 54 | if (is_array($fops)) { 55 | $fops = implode(';', $fops); 56 | } 57 | $params = array('bucket' => $bucket, 'key' => $key, 'fops' => $fops); 58 | \Qiniu\setWithoutEmpty($params, 'pipeline', $pipeline); 59 | \Qiniu\setWithoutEmpty($params, 'notifyURL', $notify_url); 60 | if ($force) { 61 | $params['force'] = 1; 62 | } 63 | $data = http_build_query($params); 64 | $scheme = "http://"; 65 | if ($this->config->useHTTPS === true) { 66 | $scheme = "https://"; 67 | } 68 | $url = $scheme . Config::API_HOST . '/pfop/'; 69 | $headers = $this->auth->authorization($url, $data, 'application/x-www-form-urlencoded'); 70 | $headers['Content-Type'] = 'application/x-www-form-urlencoded'; 71 | $response = Client::post($url, $data, $headers); 72 | if (!$response->ok()) { 73 | return array(null, new Error($url, $response)); 74 | } 75 | $r = $response->json(); 76 | $id = $r['persistentId']; 77 | return array($id, null); 78 | } 79 | 80 | public function status($id) 81 | { 82 | $scheme = "http://"; 83 | 84 | if ($this->config->useHTTPS === true) { 85 | $scheme = "https://"; 86 | } 87 | $url = $scheme . Config::API_HOST . "/status/get/prefop?id=$id"; 88 | $response = Client::get($url); 89 | if (!$response->ok()) { 90 | return array(null, new Error($url, $response)); 91 | } 92 | return array($response->json(), null); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Storage/BucketManager.php: -------------------------------------------------------------------------------- 1 | auth = $auth; 23 | if ($config == null) { 24 | $this->config = new Config(); 25 | } else { 26 | $this->config = $config; 27 | } 28 | } 29 | 30 | /** 31 | * 获取指定账号下所有的空间名。 32 | * 33 | * @return string[] 包含所有空间名 34 | */ 35 | public function buckets($shared = true) 36 | { 37 | $includeShared = "false"; 38 | if ($shared === true) { 39 | $includeShared = "true"; 40 | } 41 | return $this->rsGet('/buckets?shared=' . $includeShared); 42 | } 43 | 44 | /** 45 | * 获取指定空间绑定的所有的域名 46 | * 47 | * @return string[] 包含所有空间域名 48 | */ 49 | public function domains($bucket) 50 | { 51 | return $this->apiGet('/v6/domain/list?tbl=' . $bucket); 52 | } 53 | 54 | /** 55 | * 获取空间绑定的域名列表 56 | * @return string[] 包含空间绑定的所有域名 57 | */ 58 | 59 | /** 60 | * 列取空间的文件列表 61 | * 62 | * @param $bucket 空间名 63 | * @param $prefix 列举前缀 64 | * @param $marker 列举标识符 65 | * @param $limit 单次列举个数限制 66 | * @param $delimiter 指定目录分隔符 67 | * 68 | * @return array 包含文件信息的数组,类似:[ 69 | * { 70 | * "hash" => "", 71 | * "key" => "", 72 | * "fsize" => "", 73 | * "putTime" => "" 74 | * }, 75 | * ... 76 | * ] 77 | * @link http://developer.qiniu.com/docs/v6/api/reference/rs/list.html 78 | */ 79 | public function listFiles($bucket, $prefix = null, $marker = null, $limit = 1000, $delimiter = null) 80 | { 81 | $query = array('bucket' => $bucket); 82 | \Qiniu\setWithoutEmpty($query, 'prefix', $prefix); 83 | \Qiniu\setWithoutEmpty($query, 'marker', $marker); 84 | \Qiniu\setWithoutEmpty($query, 'limit', $limit); 85 | \Qiniu\setWithoutEmpty($query, 'delimiter', $delimiter); 86 | $url = $this->getRsfHost() . '/list?' . http_build_query($query); 87 | return $this->get($url); 88 | } 89 | 90 | /** 91 | * 获取资源的元信息,但不返回文件内容 92 | * 93 | * @param $bucket 待获取信息资源所在的空间 94 | * @param $key 待获取资源的文件名 95 | * 96 | * @return array 包含文件信息的数组,类似: 97 | * [ 98 | * "hash" => "", 99 | * "key" => "", 100 | * "fsize" => , 101 | * "putTime" => "" 102 | * "fileType" => 103 | * ] 104 | * 105 | * @link http://developer.qiniu.com/docs/v6/api/reference/rs/stat.html 106 | */ 107 | public function stat($bucket, $key) 108 | { 109 | $path = '/stat/' . \Qiniu\entry($bucket, $key); 110 | return $this->rsGet($path); 111 | } 112 | 113 | /** 114 | * 删除指定资源 115 | * 116 | * @param $bucket 待删除资源所在的空间 117 | * @param $key 待删除资源的文件名 118 | * 119 | * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error 120 | * @link http://developer.qiniu.com/docs/v6/api/reference/rs/delete.html 121 | */ 122 | public function delete($bucket, $key) 123 | { 124 | $path = '/delete/' . \Qiniu\entry($bucket, $key); 125 | list(, $error) = $this->rsPost($path); 126 | return $error; 127 | } 128 | 129 | 130 | /** 131 | * 给资源进行重命名,本质为move操作。 132 | * 133 | * @param $bucket 待操作资源所在空间 134 | * @param $oldname 待操作资源文件名 135 | * @param $newname 目标资源文件名 136 | * 137 | * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error 138 | */ 139 | public function rename($bucket, $oldname, $newname) 140 | { 141 | return $this->move($bucket, $oldname, $bucket, $newname); 142 | } 143 | 144 | /** 145 | * 给资源进行重命名,本质为move操作。 146 | * 147 | * @param $from_bucket 待操作资源所在空间 148 | * @param $from_key 待操作资源文件名 149 | * @param $to_bucket 目标资源空间名 150 | * @param $to_key 目标资源文件名 151 | * 152 | * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error 153 | * @link http://developer.qiniu.com/docs/v6/api/reference/rs/copy.html 154 | */ 155 | public function copy($from_bucket, $from_key, $to_bucket, $to_key, $force = false) 156 | { 157 | $from = \Qiniu\entry($from_bucket, $from_key); 158 | $to = \Qiniu\entry($to_bucket, $to_key); 159 | $path = '/copy/' . $from . '/' . $to; 160 | if ($force === true) { 161 | $path .= '/force/true'; 162 | } 163 | list(, $error) = $this->rsPost($path); 164 | return $error; 165 | } 166 | 167 | /** 168 | * 将资源从一个空间到另一个空间 169 | * 170 | * @param $from_bucket 待操作资源所在空间 171 | * @param $from_key 待操作资源文件名 172 | * @param $to_bucket 目标资源空间名 173 | * @param $to_key 目标资源文件名 174 | * 175 | * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error 176 | * @link http://developer.qiniu.com/docs/v6/api/reference/rs/move.html 177 | */ 178 | public function move($from_bucket, $from_key, $to_bucket, $to_key, $force = false) 179 | { 180 | $from = \Qiniu\entry($from_bucket, $from_key); 181 | $to = \Qiniu\entry($to_bucket, $to_key); 182 | $path = '/move/' . $from . '/' . $to; 183 | if ($force) { 184 | $path .= '/force/true'; 185 | } 186 | list(, $error) = $this->rsPost($path); 187 | return $error; 188 | } 189 | 190 | /** 191 | * 主动修改指定资源的文件类型 192 | * 193 | * @param $bucket 待操作资源所在空间 194 | * @param $key 待操作资源文件名 195 | * @param $mime 待操作文件目标mimeType 196 | * 197 | * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error 198 | * @link http://developer.qiniu.com/docs/v6/api/reference/rs/chgm.html 199 | */ 200 | public function changeMime($bucket, $key, $mime) 201 | { 202 | $resource = \Qiniu\entry($bucket, $key); 203 | $encode_mime = \Qiniu\base64_urlSafeEncode($mime); 204 | $path = '/chgm/' . $resource . '/mime/' . $encode_mime; 205 | list(, $error) = $this->rsPost($path); 206 | return $error; 207 | } 208 | 209 | 210 | /** 211 | * 修改指定资源的存储类型 212 | * 213 | * @param $bucket 待操作资源所在空间 214 | * @param $key 待操作资源文件名 215 | * @param $fileType 待操作文件目标文件类型 216 | * 217 | * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error 218 | * @link https://developer.qiniu.com/kodo/api/3710/modify-the-file-type 219 | */ 220 | public function changeType($bucket, $key, $fileType) 221 | { 222 | $resource = \Qiniu\entry($bucket, $key); 223 | $path = '/chtype/' . $resource . '/type/' . $fileType; 224 | list(, $error) = $this->rsPost($path); 225 | return $error; 226 | } 227 | 228 | /** 229 | * 修改文件的存储状态,即禁用状态和启用状态间的的互相转换 230 | * 231 | * @param $bucket 待操作资源所在空间 232 | * @param $key 待操作资源文件名 233 | * @param $status 待操作文件目标文件类型 234 | * 235 | * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error 236 | * @link https://developer.qiniu.com/kodo/api/4173/modify-the-file-status 237 | */ 238 | public function changeStatus($bucket, $key, $status) 239 | { 240 | $resource = \Qiniu\entry($bucket, $key); 241 | $path = '/chstatus/' . $resource . '/status/' . $status; 242 | list(, $error) = $this->rsPost($path); 243 | return $error; 244 | } 245 | 246 | /** 247 | * 从指定URL抓取资源,并将该资源存储到指定空间中 248 | * 249 | * @param $url 指定的URL 250 | * @param $bucket 目标资源空间 251 | * @param $key 目标资源文件名 252 | * 253 | * @return array 包含已拉取的文件信息。 254 | * 成功时: [ 255 | * [ 256 | * "hash" => "", 257 | * "key" => "" 258 | * ], 259 | * null 260 | * ] 261 | * 262 | * 失败时: [ 263 | * null, 264 | * Qiniu/Http/Error 265 | * ] 266 | * @link http://developer.qiniu.com/docs/v6/api/reference/rs/fetch.html 267 | */ 268 | public function fetch($url, $bucket, $key = null) 269 | { 270 | 271 | $resource = \Qiniu\base64_urlSafeEncode($url); 272 | $to = \Qiniu\entry($bucket, $key); 273 | $path = '/fetch/' . $resource . '/to/' . $to; 274 | 275 | $ak = $this->auth->getAccessKey(); 276 | $ioHost = $this->config->getIovipHost($ak, $bucket); 277 | 278 | $url = $ioHost . $path; 279 | return $this->post($url, null); 280 | } 281 | 282 | /** 283 | * 从镜像源站抓取资源到空间中,如果空间中已经存在,则覆盖该资源 284 | * 285 | * @param $bucket 待获取资源所在的空间 286 | * @param $key 代获取资源文件名 287 | * 288 | * @return mixed 成功返回NULL,失败返回对象Qiniu\Http\Error 289 | * @link http://developer.qiniu.com/docs/v6/api/reference/rs/prefetch.html 290 | */ 291 | public function prefetch($bucket, $key) 292 | { 293 | $resource = \Qiniu\entry($bucket, $key); 294 | $path = '/prefetch/' . $resource; 295 | 296 | $ak = $this->auth->getAccessKey(); 297 | $ioHost = $this->config->getIovipHost($ak, $bucket); 298 | 299 | $url = $ioHost . $path; 300 | list(, $error) = $this->post($url, null); 301 | return $error; 302 | } 303 | 304 | /** 305 | * 在单次请求中进行多个资源管理操作 306 | * 307 | * @param $operations 资源管理操作数组 308 | * 309 | * @return array 每个资源的处理情况,结果类似: 310 | * [ 311 | * { "code" => , "data" => }, 312 | * { "code" => }, 313 | * { "code" => }, 314 | * { "code" => }, 315 | * { "code" => , "data" => { "error": "" } }, 316 | * ... 317 | * ] 318 | * @link http://developer.qiniu.com/docs/v6/api/reference/rs/batch.html 319 | */ 320 | public function batch($operations) 321 | { 322 | $params = 'op=' . implode('&op=', $operations); 323 | return $this->rsPost('/batch', $params); 324 | } 325 | 326 | /** 327 | * 设置文件的生命周期 328 | * 329 | * @param $bucket 设置文件生命周期文件所在的空间 330 | * @param $key 设置文件生命周期文件的文件名 331 | * @param $days 设置该文件多少天后删除,当$days设置为0时表示取消该文件的生命周期 332 | * 333 | * @return Mixed 334 | * @link https://developer.qiniu.com/kodo/api/update-file-lifecycle 335 | */ 336 | public function deleteAfterDays($bucket, $key, $days) 337 | { 338 | $entry = \Qiniu\entry($bucket, $key); 339 | $path = "/deleteAfterDays/$entry/$days"; 340 | list(, $error) = $this->rsPost($path); 341 | return $error; 342 | } 343 | 344 | private function getRsfHost() 345 | { 346 | $scheme = "http://"; 347 | if ($this->config->useHTTPS == true) { 348 | $scheme = "https://"; 349 | } 350 | return $scheme . Config::RSF_HOST; 351 | } 352 | 353 | private function getRsHost() 354 | { 355 | $scheme = "http://"; 356 | if ($this->config->useHTTPS == true) { 357 | $scheme = "https://"; 358 | } 359 | return $scheme . Config::RS_HOST; 360 | } 361 | 362 | private function getApiHost() 363 | { 364 | $scheme = "http://"; 365 | if ($this->config->useHTTPS == true) { 366 | $scheme = "https://"; 367 | } 368 | return $scheme . Config::API_HOST; 369 | } 370 | 371 | private function rsPost($path, $body = null) 372 | { 373 | $url = $this->getRsHost() . $path; 374 | return $this->post($url, $body); 375 | } 376 | 377 | private function apiGet($path) 378 | { 379 | $url = $this->getApiHost() . $path; 380 | return $this->get($url); 381 | } 382 | 383 | private function rsGet($path) 384 | { 385 | $url = $this->getRsHost() . $path; 386 | return $this->get($url); 387 | } 388 | 389 | private function get($url) 390 | { 391 | $headers = $this->auth->authorization($url); 392 | $ret = Client::get($url, $headers); 393 | if (!$ret->ok()) { 394 | return array(null, new Error($url, $ret)); 395 | } 396 | return array($ret->json(), null); 397 | } 398 | 399 | private function post($url, $body) 400 | { 401 | $headers = $this->auth->authorization($url, $body, 'application/x-www-form-urlencoded'); 402 | $ret = Client::post($url, $body, $headers); 403 | if (!$ret->ok()) { 404 | return array(null, new Error($url, $ret)); 405 | } 406 | $r = ($ret->body === null) ? array() : $ret->json(); 407 | return array($r, null); 408 | } 409 | 410 | public static function buildBatchCopy($source_bucket, $key_pairs, $target_bucket, $force) 411 | { 412 | return self::twoKeyBatch('/copy', $source_bucket, $key_pairs, $target_bucket, $force); 413 | } 414 | 415 | 416 | public static function buildBatchRename($bucket, $key_pairs, $force) 417 | { 418 | return self::buildBatchMove($bucket, $key_pairs, $bucket, $force); 419 | } 420 | 421 | 422 | public static function buildBatchMove($source_bucket, $key_pairs, $target_bucket, $force) 423 | { 424 | return self::twoKeyBatch('/move', $source_bucket, $key_pairs, $target_bucket, $force); 425 | } 426 | 427 | 428 | public static function buildBatchDelete($bucket, $keys) 429 | { 430 | return self::oneKeyBatch('/delete', $bucket, $keys); 431 | } 432 | 433 | 434 | public static function buildBatchStat($bucket, $keys) 435 | { 436 | return self::oneKeyBatch('/stat', $bucket, $keys); 437 | } 438 | 439 | public static function buildBatchDeleteAfterDays($bucket, $key_day_pairs) 440 | { 441 | $data = array(); 442 | foreach ($key_day_pairs as $key => $day) { 443 | array_push($data, '/deleteAfterDays/' . \Qiniu\entry($bucket, $key) . '/' . $day); 444 | } 445 | return $data; 446 | } 447 | 448 | public static function buildBatchChangeMime($bucket, $key_mime_pairs) 449 | { 450 | $data = array(); 451 | foreach ($key_mime_pairs as $key => $mime) { 452 | array_push($data, '/chgm/' . \Qiniu\entry($bucket, $key) . '/mime/' . base64_encode($mime)); 453 | } 454 | return $data; 455 | } 456 | 457 | public static function buildBatchChangeType($bucket, $key_type_pairs) 458 | { 459 | $data = array(); 460 | foreach ($key_type_pairs as $key => $type) { 461 | array_push($data, '/chtype/' . \Qiniu\entry($bucket, $key) . '/type/' . $type); 462 | } 463 | return $data; 464 | } 465 | 466 | private static function oneKeyBatch($operation, $bucket, $keys) 467 | { 468 | $data = array(); 469 | foreach ($keys as $key) { 470 | array_push($data, $operation . '/' . \Qiniu\entry($bucket, $key)); 471 | } 472 | return $data; 473 | } 474 | 475 | private static function twoKeyBatch($operation, $source_bucket, $key_pairs, $target_bucket, $force) 476 | { 477 | if ($target_bucket === null) { 478 | $target_bucket = $source_bucket; 479 | } 480 | $data = array(); 481 | $forceOp = "false"; 482 | if ($force) { 483 | $forceOp = "true"; 484 | } 485 | foreach ($key_pairs as $from_key => $to_key) { 486 | $from = \Qiniu\entry($source_bucket, $from_key); 487 | $to = \Qiniu\entry($target_bucket, $to_key); 488 | array_push($data, $operation . '/' . $from . '/' . $to . "/force/" . $forceOp); 489 | } 490 | return $data; 491 | } 492 | } 493 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Storage/FormUploader.php: -------------------------------------------------------------------------------- 1 | "", 24 | * "key" => "" 25 | * ] 26 | */ 27 | public static function put( 28 | $upToken, 29 | $key, 30 | $data, 31 | $config, 32 | $params, 33 | $mime, 34 | $fname 35 | ) { 36 | 37 | $fields = array('token' => $upToken); 38 | if ($key === null) { 39 | $fname='nullkey'; 40 | } else { 41 | $fields['key'] = $key; 42 | } 43 | 44 | //enable crc32 check by default 45 | $fields['crc32'] = \Qiniu\crc32_data($data); 46 | 47 | if ($params) { 48 | foreach ($params as $k => $v) { 49 | $fields[$k] = $v; 50 | } 51 | } 52 | 53 | list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken); 54 | if ($err != null) { 55 | return array(null, $err); 56 | } 57 | 58 | $upHost = $config->getUpHost($accessKey, $bucket); 59 | 60 | $response = Client::multipartPost($upHost, $fields, 'file', $fname, $data, $mime); 61 | if (!$response->ok()) { 62 | return array(null, new Error($upHost, $response)); 63 | } 64 | return array($response->json(), null); 65 | } 66 | 67 | /** 68 | * 上传文件到七牛,内部使用 69 | * 70 | * @param $upToken 上传凭证 71 | * @param $key 上传文件名 72 | * @param $filePath 上传文件的路径 73 | * @param $config 上传配置 74 | * @param $params 自定义变量,规格参考 75 | * http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar 76 | * @param $mime 上传数据的mimeType 77 | * 78 | * @return array 包含已上传文件的信息,类似: 79 | * [ 80 | * "hash" => "", 81 | * "key" => "" 82 | * ] 83 | */ 84 | public static function putFile( 85 | $upToken, 86 | $key, 87 | $filePath, 88 | $config, 89 | $params, 90 | $mime 91 | ) { 92 | 93 | 94 | $fields = array('token' => $upToken, 'file' => self::createFile($filePath, $mime)); 95 | if ($key !== null) { 96 | $fields['key'] = $key; 97 | } 98 | 99 | $fields['crc32'] = \Qiniu\crc32_file($filePath); 100 | 101 | if ($params) { 102 | foreach ($params as $k => $v) { 103 | $fields[$k] = $v; 104 | } 105 | } 106 | $fields['key'] = $key; 107 | $headers = array('Content-Type' => 'multipart/form-data'); 108 | 109 | list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken); 110 | if ($err != null) { 111 | return array(null, $err); 112 | } 113 | 114 | $upHost = $config->getUpHost($accessKey, $bucket); 115 | 116 | $response = Client::post($upHost, $fields, $headers); 117 | if (!$response->ok()) { 118 | return array(null, new Error($upHost, $response)); 119 | } 120 | return array($response->json(), null); 121 | } 122 | 123 | private static function createFile($filename, $mime) 124 | { 125 | // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax 126 | // See: https://wiki.php.net/rfc/curl-file-upload 127 | if (function_exists('curl_file_create')) { 128 | return curl_file_create($filename, $mime); 129 | } 130 | 131 | // Use the old style if using an older version of PHP 132 | $value = "@{$filename}"; 133 | if (!empty($mime)) { 134 | $value .= ';type=' . $mime; 135 | } 136 | 137 | return $value; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Storage/ResumeUploader.php: -------------------------------------------------------------------------------- 1 | upToken = $upToken; 51 | $this->key = $key; 52 | $this->inputStream = $inputStream; 53 | $this->size = $size; 54 | $this->params = $params; 55 | $this->mime = $mime; 56 | $this->contexts = array(); 57 | $this->config = $config; 58 | 59 | list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($upToken); 60 | if ($err != null) { 61 | return array(null, $err); 62 | } 63 | 64 | $upHost = $config->getUpHost($accessKey, $bucket); 65 | if ($err != null) { 66 | throw new \Exception($err->message(), 1); 67 | } 68 | $this->host = $upHost; 69 | } 70 | 71 | /** 72 | * 上传操作 73 | */ 74 | public function upload($fname) 75 | { 76 | $uploaded = 0; 77 | while ($uploaded < $this->size) { 78 | $blockSize = $this->blockSize($uploaded); 79 | $data = fread($this->inputStream, $blockSize); 80 | if ($data === false) { 81 | throw new \Exception("file read failed", 1); 82 | } 83 | $crc = \Qiniu\crc32_data($data); 84 | $response = $this->makeBlock($data, $blockSize); 85 | $ret = null; 86 | if ($response->ok() && $response->json() != null) { 87 | $ret = $response->json(); 88 | } 89 | if ($response->statusCode < 0) { 90 | list($accessKey, $bucket, $err) = \Qiniu\explodeUpToken($this->upToken); 91 | if ($err != null) { 92 | return array(null, $err); 93 | } 94 | 95 | $upHostBackup = $this->config->getUpBackupHost($accessKey, $bucket); 96 | $this->host = $upHostBackup; 97 | } 98 | if ($response->needRetry() || !isset($ret['crc32']) || $crc != $ret['crc32']) { 99 | $response = $this->makeBlock($data, $blockSize); 100 | $ret = $response->json(); 101 | } 102 | 103 | if (!$response->ok() || !isset($ret['crc32']) || $crc != $ret['crc32']) { 104 | return array(null, new Error($this->currentUrl, $response)); 105 | } 106 | array_push($this->contexts, $ret['ctx']); 107 | $uploaded += $blockSize; 108 | } 109 | return $this->makeFile($fname); 110 | } 111 | 112 | /** 113 | * 创建块 114 | */ 115 | private function makeBlock($block, $blockSize) 116 | { 117 | $url = $this->host . '/mkblk/' . $blockSize; 118 | return $this->post($url, $block); 119 | } 120 | 121 | private function fileUrl($fname) 122 | { 123 | $url = $this->host . '/mkfile/' . $this->size; 124 | $url .= '/mimeType/' . \Qiniu\base64_urlSafeEncode($this->mime); 125 | if ($this->key != null) { 126 | $url .= '/key/' . \Qiniu\base64_urlSafeEncode($this->key); 127 | } 128 | $url .= '/fname/' . \Qiniu\base64_urlSafeEncode($fname); 129 | if (!empty($this->params)) { 130 | foreach ($this->params as $key => $value) { 131 | $val = \Qiniu\base64_urlSafeEncode($value); 132 | $url .= "/$key/$val"; 133 | } 134 | } 135 | return $url; 136 | } 137 | 138 | /** 139 | * 创建文件 140 | */ 141 | private function makeFile($fname) 142 | { 143 | $url = $this->fileUrl($fname); 144 | $body = implode(',', $this->contexts); 145 | $response = $this->post($url, $body); 146 | if ($response->needRetry()) { 147 | $response = $this->post($url, $body); 148 | } 149 | if (!$response->ok()) { 150 | return array(null, new Error($this->currentUrl, $response)); 151 | } 152 | return array($response->json(), null); 153 | } 154 | 155 | private function post($url, $data) 156 | { 157 | $this->currentUrl = $url; 158 | $headers = array('Authorization' => 'UpToken ' . $this->upToken); 159 | return Client::post($url, $data, $headers); 160 | } 161 | 162 | private function blockSize($uploaded) 163 | { 164 | if ($this->size < $uploaded + Config::BLOCK_SIZE) { 165 | return $this->size - $uploaded; 166 | } 167 | return Config::BLOCK_SIZE; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Storage/UploadManager.php: -------------------------------------------------------------------------------- 1 | config = $config; 24 | } 25 | 26 | /** 27 | * 上传二进制流到七牛 28 | * 29 | * @param $upToken 上传凭证 30 | * @param $key 上传文件名 31 | * @param $data 上传二进制流 32 | * @param $params 自定义变量,规格参考 33 | * http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar 34 | * @param $mime 上传数据的mimeType 35 | * @param $checkCrc 是否校验crc32 36 | * 37 | * @return array 包含已上传文件的信息,类似: 38 | * [ 39 | * "hash" => "", 40 | * "key" => "" 41 | * ] 42 | */ 43 | public function put( 44 | $upToken, 45 | $key, 46 | $data, 47 | $params = null, 48 | $mime = 'application/octet-stream', 49 | $fname = null 50 | ) { 51 | 52 | $params = self::trimParams($params); 53 | return FormUploader::put( 54 | $upToken, 55 | $key, 56 | $data, 57 | $this->config, 58 | $params, 59 | $mime, 60 | $fname 61 | ); 62 | } 63 | 64 | 65 | /** 66 | * 上传文件到七牛 67 | * 68 | * @param $upToken 上传凭证 69 | * @param $key 上传文件名 70 | * @param $filePath 上传文件的路径 71 | * @param $params 自定义变量,规格参考 72 | * http://developer.qiniu.com/docs/v6/api/overview/up/response/vars.html#xvar 73 | * @param $mime 上传数据的mimeType 74 | * @param $checkCrc 是否校验crc32 75 | * 76 | * @return array 包含已上传文件的信息,类似: 77 | * [ 78 | * "hash" => "", 79 | * "key" => "" 80 | * ] 81 | */ 82 | public function putFile( 83 | $upToken, 84 | $key, 85 | $filePath, 86 | $params = null, 87 | $mime = 'application/octet-stream', 88 | $checkCrc = false 89 | ) { 90 | 91 | $file = fopen($filePath, 'rb'); 92 | if ($file === false) { 93 | throw new \Exception("file can not open", 1); 94 | } 95 | $params = self::trimParams($params); 96 | $stat = fstat($file); 97 | $size = $stat['size']; 98 | if ($size <= Config::BLOCK_SIZE) { 99 | $data = fread($file, $size); 100 | fclose($file); 101 | if ($data === false) { 102 | throw new \Exception("file can not read", 1); 103 | } 104 | return FormUploader::put( 105 | $upToken, 106 | $key, 107 | $data, 108 | $this->config, 109 | $params, 110 | $mime, 111 | basename($filePath) 112 | ); 113 | } 114 | 115 | $up = new ResumeUploader( 116 | $upToken, 117 | $key, 118 | $file, 119 | $size, 120 | $params, 121 | $mime, 122 | $this->config 123 | ); 124 | $ret = $up->upload(basename($filePath)); 125 | fclose($file); 126 | return $ret; 127 | } 128 | 129 | public static function trimParams($params) 130 | { 131 | if ($params === null) { 132 | return null; 133 | } 134 | $ret = array(); 135 | foreach ($params as $k => $v) { 136 | $pos = strpos($k, 'x:'); 137 | if ($pos === 0 && !empty($v)) { 138 | $ret[$k] = $v; 139 | } 140 | } 141 | return $ret; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/Zone.php: -------------------------------------------------------------------------------- 1 | srcUpHosts = $srcUpHosts; 34 | $this->cdnUpHosts = $cdnUpHosts; 35 | $this->rsHost = $rsHost; 36 | $this->rsfHost = $rsfHost; 37 | $this->apiHost = $apiHost; 38 | $this->iovipHost = $iovipHost; 39 | } 40 | 41 | //华东机房 42 | public static function zone0() 43 | { 44 | $Zone_z0 = new Zone( 45 | array("up.qiniup.com", 'up-jjh.qiniup.com', 'up-xs.qiniup.com'), 46 | array('upload.qiniup.com', 'upload-jjh.qiniup.com', 'upload-xs.qiniup.com'), 47 | 'rs.qiniu.com', 48 | 'rsf.qiniu.com', 49 | 'api.qiniu.com', 50 | 'iovip.qbox.me' 51 | ); 52 | return $Zone_z0; 53 | } 54 | 55 | //华北机房 56 | public static function zone1() 57 | { 58 | $Zone_z1 = new Zone( 59 | array('up-z1.qiniup.com'), 60 | array('upload-z1.qiniup.com'), 61 | "rs-z1.qiniu.com", 62 | "rsf-z1.qiniu.com", 63 | "api-z1.qiniu.com", 64 | "iovip-z1.qbox.me" 65 | ); 66 | 67 | return $Zone_z1; 68 | } 69 | 70 | //华南机房 71 | public static function zone2() 72 | { 73 | $Zone_z2 = new Zone( 74 | array('up-z2.qiniup.com', 'up-dg.qiniup.com', 'up-fs.qiniup.com'), 75 | array('upload-z2.qiniup.com', 'upload-dg.qiniup.com', 'upload-fs.qiniup.com'), 76 | "rs-z2.qiniu.com", 77 | "rsf-z2.qiniu.com", 78 | "api-z2.qiniu.com", 79 | "iovip-z2.qbox.me" 80 | ); 81 | return $Zone_z2; 82 | } 83 | 84 | //北美机房 85 | public static function zoneNa0() 86 | { 87 | //北美机房 88 | $Zone_na0 = new Zone( 89 | array('up-na0.qiniup.com'), 90 | array('upload-na0.qiniup.com'), 91 | "rs-na0.qiniu.com", 92 | "rsf-na0.qiniu.com", 93 | "api-na0.qiniu.com", 94 | "iovip-na0.qbox.me" 95 | ); 96 | return $Zone_na0; 97 | } 98 | 99 | //新加坡机房 100 | public static function zoneAs0() 101 | { 102 | //新加坡机房 103 | $Zone_as0 = new Zone( 104 | array('up-as0.qiniup.com'), 105 | array('upload-as0.qiniup.com'), 106 | "rs-as0.qiniu.com", 107 | "rsf-as0.qiniu.com", 108 | "api-as0.qiniu.com", 109 | "iovip-as0.qbox.me" 110 | ); 111 | return $Zone_as0; 112 | } 113 | 114 | /* 115 | * GET /v2/query?ak=&&bucket= 116 | **/ 117 | public static function queryZone($ak, $bucket) 118 | { 119 | $zone = new Zone(); 120 | $url = Config::UC_HOST . '/v2/query' . "?ak=$ak&bucket=$bucket"; 121 | $ret = Client::Get($url); 122 | if (!$ret->ok()) { 123 | return array(null, new Error($url, $ret)); 124 | } 125 | $r = ($ret->body === null) ? array() : $ret->json(); 126 | //print_r($ret); 127 | //parse zone; 128 | 129 | $iovipHost = $r['io']['src']['main'][0]; 130 | $zone->iovipHost = $iovipHost; 131 | $accMain = $r['up']['acc']['main'][0]; 132 | array_push($zone->cdnUpHosts, $accMain); 133 | if (isset($r['up']['acc']['backup'])) { 134 | foreach ($r['up']['acc']['backup'] as $key => $value) { 135 | array_push($zone->cdnUpHosts, $value); 136 | } 137 | } 138 | $srcMain = $r['up']['src']['main'][0]; 139 | array_push($zone->srcUpHosts, $srcMain); 140 | if (isset($r['up']['src']['backup'])) { 141 | foreach ($r['up']['src']['backup'] as $key => $value) { 142 | array_push($zone->srcUpHosts, $value); 143 | } 144 | } 145 | 146 | //set specific hosts 147 | if (strstr($zone->iovipHost, "z1") !== false) { 148 | $zone->rsHost = "rs-z1.qiniu.com"; 149 | $zone->rsfHost = "rsf-z1.qiniu.com"; 150 | $zone->apiHost = "api-z1.qiniu.com"; 151 | } elseif (strstr($zone->iovipHost, "z2") !== false) { 152 | $zone->rsHost = "rs-z2.qiniu.com"; 153 | $zone->rsfHost = "rsf-z2.qiniu.com"; 154 | $zone->apiHost = "api-z2.qiniu.com"; 155 | } elseif (strstr($zone->iovipHost, "na0") !== false) { 156 | $zone->rsHost = "rs-na0.qiniu.com"; 157 | $zone->rsfHost = "rsf-na0.qiniu.com"; 158 | $zone->apiHost = "api-na0.qiniu.com"; 159 | } elseif (strstr($zone->iovipHost, "as0") !== false) { 160 | $zone->rsHost = "rs-as0.qiniu.com"; 161 | $zone->rsfHost = "rsf-as0.qiniu.com"; 162 | $zone->apiHost = "api-as0.qiniu.com"; 163 | } else { 164 | $zone->rsHost = "rs.qiniu.com"; 165 | $zone->rsfHost = "rsf.qiniu.com"; 166 | $zone->apiHost = "api.qiniu.com"; 167 | } 168 | 169 | return $zone; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /cloud/qiniu/src/Qiniu/functions.php: -------------------------------------------------------------------------------- 1 | 'JSON_ERROR_DEPTH - Maximum stack depth exceeded', 84 | JSON_ERROR_STATE_MISMATCH => 'JSON_ERROR_STATE_MISMATCH - Underflow or the modes mismatch', 85 | JSON_ERROR_CTRL_CHAR => 'JSON_ERROR_CTRL_CHAR - Unexpected control character found', 86 | JSON_ERROR_SYNTAX => 'JSON_ERROR_SYNTAX - Syntax error, malformed JSON', 87 | JSON_ERROR_UTF8 => 'JSON_ERROR_UTF8 - Malformed UTF-8 characters, possibly incorrectly encoded' 88 | ); 89 | 90 | if (empty($json)) { 91 | return null; 92 | } 93 | $data = \json_decode($json, $assoc, $depth); 94 | 95 | if (JSON_ERROR_NONE !== json_last_error()) { 96 | $last = json_last_error(); 97 | throw new \InvalidArgumentException( 98 | 'Unable to parse JSON data: ' 99 | . (isset($jsonErrors[$last]) 100 | ? $jsonErrors[$last] 101 | : 'Unknown error') 102 | ); 103 | } 104 | 105 | return $data; 106 | } 107 | 108 | /** 109 | * 计算七牛API中的数据格式 110 | * 111 | * @param $bucket 待操作的空间名 112 | * @param $key 待操作的文件名 113 | * 114 | * @return string 符合七牛API规格的数据格式 115 | * @link http://developer.qiniu.com/docs/v6/api/reference/data-formats.html 116 | */ 117 | function entry($bucket, $key) 118 | { 119 | $en = $bucket; 120 | if (!empty($key)) { 121 | $en = $bucket . ':' . $key; 122 | } 123 | return base64_urlSafeEncode($en); 124 | } 125 | 126 | /** 127 | * array 辅助方法,无值时不set 128 | * 129 | * @param $array 待操作array 130 | * @param $key key 131 | * @param $value value 为null时 不设置 132 | * 133 | * @return array 原来的array,便于连续操作 134 | */ 135 | function setWithoutEmpty(&$array, $key, $value) 136 | { 137 | if (!empty($value)) { 138 | $array[$key] = $value; 139 | } 140 | return $array; 141 | } 142 | 143 | /** 144 | * 缩略图链接拼接 145 | * 146 | * @param string $url 图片链接 147 | * @param int $mode 缩略模式 148 | * @param int $width 宽度 149 | * @param int $height 长度 150 | * @param string $format 输出类型 151 | * @param int $quality 图片质量 152 | * @param int $interlace 是否支持渐进显示 153 | * @param int $ignoreError 忽略结果 154 | * @return string 155 | * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/imageview2.html 156 | * @author Sherlock Ren 157 | */ 158 | function thumbnail( 159 | $url, 160 | $mode, 161 | $width, 162 | $height, 163 | $format = null, 164 | $quality = null, 165 | $interlace = null, 166 | $ignoreError = 1 167 | ) { 168 | 169 | static $imageUrlBuilder = null; 170 | if (is_null($imageUrlBuilder)) { 171 | $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; 172 | } 173 | 174 | return call_user_func_array(array($imageUrlBuilder, 'thumbnail'), func_get_args()); 175 | } 176 | 177 | /** 178 | * 图片水印 179 | * 180 | * @param string $url 图片链接 181 | * @param string $image 水印图片链接 182 | * @param numeric $dissolve 透明度 183 | * @param string $gravity 水印位置 184 | * @param numeric $dx 横轴边距 185 | * @param numeric $dy 纵轴边距 186 | * @param numeric $watermarkScale 自适应原图的短边比例 187 | * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html 188 | * @return string 189 | * @author Sherlock Ren 190 | */ 191 | function waterImg( 192 | $url, 193 | $image, 194 | $dissolve = 100, 195 | $gravity = 'SouthEast', 196 | $dx = null, 197 | $dy = null, 198 | $watermarkScale = null 199 | ) { 200 | 201 | static $imageUrlBuilder = null; 202 | if (is_null($imageUrlBuilder)) { 203 | $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; 204 | } 205 | 206 | return call_user_func_array(array($imageUrlBuilder, 'waterImg'), func_get_args()); 207 | } 208 | 209 | /** 210 | * 文字水印 211 | * 212 | * @param string $url 图片链接 213 | * @param string $text 文字 214 | * @param string $font 文字字体 215 | * @param string $fontSize 文字字号 216 | * @param string $fontColor 文字颜色 217 | * @param numeric $dissolve 透明度 218 | * @param string $gravity 水印位置 219 | * @param numeric $dx 横轴边距 220 | * @param numeric $dy 纵轴边距 221 | * @link http://developer.qiniu.com/code/v6/api/kodo-api/image/watermark.html#text-watermark 222 | * @return string 223 | * @author Sherlock Ren 224 | */ 225 | function waterText( 226 | $url, 227 | $text, 228 | $font = '黑体', 229 | $fontSize = 0, 230 | $fontColor = null, 231 | $dissolve = 100, 232 | $gravity = 'SouthEast', 233 | $dx = null, 234 | $dy = null 235 | ) { 236 | 237 | static $imageUrlBuilder = null; 238 | if (is_null($imageUrlBuilder)) { 239 | $imageUrlBuilder = new \Qiniu\Processing\ImageUrlBuilder; 240 | } 241 | 242 | return call_user_func_array(array($imageUrlBuilder, 'waterText'), func_get_args()); 243 | } 244 | 245 | /** 246 | * 从uptoken解析accessKey和bucket 247 | * 248 | * @param $upToken 249 | * @return array(ak,bucket,err=null) 250 | */ 251 | function explodeUpToken($upToken) 252 | { 253 | $items = explode(':', $upToken); 254 | if (count($items) != 3) { 255 | return array(null, null, "invalid uptoken"); 256 | } 257 | $accessKey = $items[0]; 258 | $putPolicy = json_decode(base64_decode($items[2])); 259 | $scope = $putPolicy->scope; 260 | $scopeItems = explode(':', $scope); 261 | $bucket = $scopeItems[0]; 262 | return array($accessKey, $bucket, null); 263 | } 264 | } 265 | -------------------------------------------------------------------------------- /css/border-anim-h.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/border-anim-h.gif -------------------------------------------------------------------------------- /css/border-anim-v.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/border-anim-v.gif -------------------------------------------------------------------------------- /css/graphics/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/close.png -------------------------------------------------------------------------------- /css/graphics/closeX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/closeX.png -------------------------------------------------------------------------------- /css/graphics/controlbar-black-border.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/controlbar-black-border.gif -------------------------------------------------------------------------------- /css/graphics/controlbar-text-buttons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/controlbar-text-buttons.png -------------------------------------------------------------------------------- /css/graphics/controlbar-white-small.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/controlbar-white-small.gif -------------------------------------------------------------------------------- /css/graphics/controlbar-white.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/controlbar-white.gif -------------------------------------------------------------------------------- /css/graphics/controlbar2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/controlbar2.gif -------------------------------------------------------------------------------- /css/graphics/controlbar3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/controlbar3.gif -------------------------------------------------------------------------------- /css/graphics/controlbar4-hover.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/controlbar4-hover.gif -------------------------------------------------------------------------------- /css/graphics/controlbar4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/controlbar4.gif -------------------------------------------------------------------------------- /css/graphics/fullexpand.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/fullexpand.gif -------------------------------------------------------------------------------- /css/graphics/geckodimmer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/geckodimmer.png -------------------------------------------------------------------------------- /css/graphics/icon.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/icon.gif -------------------------------------------------------------------------------- /css/graphics/loader.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/loader.gif -------------------------------------------------------------------------------- /css/graphics/loader.white.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/loader.white.gif -------------------------------------------------------------------------------- /css/graphics/outlines/beveled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/outlines/beveled.png -------------------------------------------------------------------------------- /css/graphics/outlines/drop-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/outlines/drop-shadow.png -------------------------------------------------------------------------------- /css/graphics/outlines/glossy-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/outlines/glossy-dark.png -------------------------------------------------------------------------------- /css/graphics/outlines/outer-glow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/outlines/outer-glow.png -------------------------------------------------------------------------------- /css/graphics/outlines/rounded-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/outlines/rounded-black.png -------------------------------------------------------------------------------- /css/graphics/outlines/rounded-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/outlines/rounded-white.png -------------------------------------------------------------------------------- /css/graphics/resize.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/resize.gif -------------------------------------------------------------------------------- /css/graphics/scrollarrows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/scrollarrows.png -------------------------------------------------------------------------------- /css/graphics/zoomin.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/zoomin.cur -------------------------------------------------------------------------------- /css/graphics/zoomout.cur: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jzwalk/HighSlide/58f101f0804b1be4fe1369a6e56175734ae89601/css/graphics/zoomout.cur -------------------------------------------------------------------------------- /css/highslide-ie6.css: -------------------------------------------------------------------------------- 1 | .closebutton { 2 | /* NOTE! This URL is relative to the HTML page, not the CSS */ 3 | filter:progid:DXImageTransform.Microsoft.AlphaImageLoader( 4 | src='../highslide/graphics/close.png', sizingMethod='scale'); 5 | 6 | background: none; 7 | cursor: hand; 8 | } 9 | 10 | /* Viewport fixed hack */ 11 | .highslide-viewport { 12 | position: absolute; 13 | left: expression( ( ( ignoreMe1 = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft ) ) + 'px' ); 14 | top: expression( ( ignoreMe2 = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ) + 'px' ); 15 | width: expression( ( ( ignoreMe3 = document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth ) ) + 'px' ); 16 | height: expression( ( ( ignoreMe4 = document.documentElement.clientHeight ? document.documentElement.clientHeight : document.body.clientHeight ) ) + 'px' ); 17 | } 18 | 19 | /* Thumbstrip PNG fix */ 20 | .highslide-scroll-down, .highslide-scroll-up { 21 | position: relative; 22 | overflow: hidden; 23 | } 24 | .highslide-scroll-down div, .highslide-scroll-up div { 25 | /* NOTE! This URL is relative to the HTML page, not the CSS */ 26 | filter:progid:DXImageTransform.Microsoft.AlphaImageLoader( 27 | src='../highslide/graphics/scrollarrows.png', sizingMethod='scale'); 28 | background: none !important; 29 | position: absolute; 30 | cursor: hand; 31 | width: 75px; 32 | height: 75px !important; 33 | } 34 | .highslide-thumbstrip-horizontal .highslide-scroll-down div { 35 | left: -50px; 36 | top: -15px; 37 | } 38 | .highslide-thumbstrip-horizontal .highslide-scroll-up div { 39 | top: -15px; 40 | } 41 | .highslide-thumbstrip-vertical .highslide-scroll-down div { 42 | top: -50px; 43 | } 44 | 45 | /* Thumbstrip marker arrow trasparent background fix */ 46 | .highslide-thumbstrip .highslide-marker { 47 | border-color: white; /* match the background */ 48 | } 49 | .dark .highslide-thumbstrip-horizontal .highslide-marker { 50 | border-color: #111; 51 | } 52 | .highslide-viewport .highslide-marker { 53 | border-color: #333; 54 | } 55 | .highslide-thumbstrip { 56 | float: left; 57 | } 58 | 59 | /* Positioning fixes for the control bar */ 60 | .text-controls .highslide-controls { 61 | width: 480px; 62 | } 63 | .text-controls a span { 64 | width: 4em; 65 | } 66 | .text-controls .highslide-full-expand a span { 67 | width: 0; 68 | } 69 | .text-controls .highslide-close a span { 70 | width: 0; 71 | } 72 | 73 | /* Special */ 74 | .in-page .highslide-thumbstrip-horizontal .highslide-marker { 75 | border-bottom: gray; 76 | } 77 | -------------------------------------------------------------------------------- /css/imgareaselect-animated.css: -------------------------------------------------------------------------------- 1 | /* 2 | * ias animated border style 3 | */ 4 | 5 | .ias-border1 { 6 | background: url(border-anim-v.gif) repeat-y left top; 7 | } 8 | 9 | .ias-border2 { 10 | background: url(border-anim-h.gif) repeat-x left top; 11 | } 12 | 13 | .ias-border3 { 14 | background: url(border-anim-v.gif) repeat-y right top; 15 | } 16 | 17 | .ias-border4 { 18 | background: url(border-anim-h.gif) repeat-x left bottom; 19 | } 20 | 21 | .ias-border1, .ias-border2, 22 | .ias-border3, .ias-border4 { 23 | filter: alpha(opacity=50); 24 | opacity: 0.5; 25 | } 26 | 27 | .ias-handle { 28 | background-color: #fff; 29 | border: solid 1px #000; 30 | filter: alpha(opacity=50); 31 | opacity: 0.5; 32 | } 33 | 34 | .ias-outer { 35 | background-color: #000; 36 | filter: alpha(opacity=50); 37 | opacity: 0.5; 38 | } 39 | 40 | .ias-selection { 41 | } -------------------------------------------------------------------------------- /js/imgareaselect.js: -------------------------------------------------------------------------------- 1 | eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('(m($){18 W=2v.4T,D=2v.4S,F=2v.4R,u=2v.4Q;m V(){C $("<4P/>")};$.N=m(T,c){18 O=$(T),1F,A=V(),1k=V(),I=V().r(V()).r(V()).r(V()),B=V().r(V()).r(V()).r(V()),E=$([]),1K,G,l,17={v:0,l:0},Q,M,1l,1g={v:0,l:0},12=0,1J="1H",2k,2j,1t,1s,S,1B,1A,2o,2n,14,1Q,a,b,j,g,f={a:0,b:0,j:0,g:0,H:0,L:0},2u=R.4O,1M=4N.4M,$p,d,i,o,w,h,2p;m 1n(x){C x+17.v-1g.v};m 1m(y){C y+17.l-1g.l};m 1b(x){C x-17.v+1g.v};m 1a(y){C y-17.l+1g.l};m 1z(3J){C 3J.4L-1g.v};m 1y(3I){C 3I.4K-1g.l};m 13(32){18 1i=32||1t,1h=32||1s;C{a:u(f.a*1i),b:u(f.b*1h),j:u(f.j*1i),g:u(f.g*1h),H:u(f.j*1i)-u(f.a*1i),L:u(f.g*1h)-u(f.b*1h)}};m 23(a,b,j,g,31){18 1i=31||1t,1h=31||1s;f={a:u(a/1i||0),b:u(b/1h||0),j:u(j/1i||0),g:u(g/1h||0)};f.H=f.j-f.a;f.L=f.g-f.b};m 1f(){9(!1F||!O.H()){C}17={v:u(O.2t().v),l:u(O.2t().l)};Q=O.2Y();M=O.3H();17.l+=(O.30()-M)>>1;17.v+=(O.2q()-Q)>>1;1B=u(c.4J/1t)||0;1A=u(c.4I/1s)||0;2o=u(F(c.4H/1t||1<<24,Q));2n=u(F(c.4G/1s||1<<24,M));9($().4F=="1.3.2"&&1J=="21"&&!2u["4E"]){17.l+=D(R.1q.2r,2u.2r);17.v+=D(R.1q.2s,2u.2s)}1g=/1H|4D/.1c(1l.q("1p"))?{v:u(1l.2t().v)-1l.2s(),l:u(1l.2t().l)-1l.2r()}:1J=="21"?{v:$(R).2s(),l:$(R).2r()}:{v:0,l:0};G=1n(0);l=1m(0);9(f.j>Q||f.g>M){1U()}};m 1V(3F){9(!1Q){C}A.q({v:1n(f.a),l:1m(f.b)}).r(1k).H(w=f.H).L(h=f.L);1k.r(I).r(E).q({v:0,l:0});I.H(D(w-I.2q()+I.2Y(),0)).L(D(h-I.30()+I.3H(),0));$(B[0]).q({v:G,l:l,H:f.a,L:M});$(B[1]).q({v:G+f.a,l:l,H:w,L:f.b});$(B[2]).q({v:G+f.j,l:l,H:Q-f.j,L:M});$(B[3]).q({v:G+f.a,l:l+f.g,H:w,L:M-f.g});w-=E.2q();h-=E.30();2O(E.3f){15 8:$(E[4]).q({v:w>>1});$(E[5]).q({v:w,l:h>>1});$(E[6]).q({v:w>>1,l:h});$(E[7]).q({l:h>>1});15 4:E.3G(1,3).q({v:w});E.3G(2,4).q({l:h})}9(3F!==Y){9($.N.2Z!=2R){$(R).U($.N.2z,$.N.2Z)}9(c.1T){$(R)[$.N.2z]($.N.2Z=2R)}}9(1j&&I.2q()-I.2Y()==2){I.q("3E",0);3x(m(){I.q("3E","4C")},0)}};m 22(3D){1f();1V(3D);a=1n(f.a);b=1m(f.b);j=1n(f.j);g=1m(f.g)};m 27(2X,2w){c.1P?2X.4B(c.1P,2w):2X.1r()};m 1d(2W){18 x=1b(1z(2W))-f.a,y=1a(1y(2W))-f.b;9(!2p){1f();2p=11;A.1G("4A",m(){2p=Y})}S="";9(c.2D){9(y<=c.1W){S="n"}X{9(y>=f.L-c.1W){S="s"}}9(x<=c.1W){S+="w"}X{9(x>=f.H-c.1W){S+="e"}}}A.q("2V",S?S+"-19":c.26?"4z":"");9(1K){1K.4y()}};m 2S(4x){$("1q").q("2V","");9(c.4w||f.H*f.L==0){27(A.r(B),m(){$(J).1r()})}$(R).U("P",2l);A.P(1d);c.2f(T,13())};m 2C(1X){9(1X.3z!=1){C Y}1f();9(S){$("1q").q("2V",S+"-19");a=1n(f[/w/.1c(S)?"j":"a"]);b=1m(f[/n/.1c(S)?"g":"b"]);$(R).P(2l).1G("1x",2S);A.U("P",1d)}X{9(c.26){2k=G+f.a-1z(1X);2j=l+f.b-1y(1X);A.U("P",1d);$(R).P(2T).1G("1x",m(){c.2f(T,13());$(R).U("P",2T);A.P(1d)})}X{O.1O(1X)}}C Y};m 1w(3C){9(14){9(3C){j=D(G,F(G+Q,a+W(g-b)*14*(j>a||-1)));g=u(D(l,F(l+M,b+W(j-a)/14*(g>b||-1))));j=u(j)}X{g=D(l,F(l+M,b+W(j-a)/14*(g>b||-1)));j=u(D(G,F(G+Q,a+W(g-b)*14*(j>a||-1))));g=u(g)}}};m 1U(){a=F(a,G+Q);b=F(b,l+M);9(W(j-a)<1B){j=a-1B*(jG+Q){a=G+Q-1B}}}9(W(g-b)<1A){g=b-1A*(gl+M){b=l+M-1A}}}j=D(G,F(j,G+Q));g=D(l,F(g,l+M));1w(W(j-a)2o){j=a-2o*(j2n){g=b-2n*(g=0){E.H(5).L(5)}9(o=c.2K){E.q({2K:o,2H:"3m"})}1R(E,{3n:"2J-28",3l:"2I-28",3o:"1e"})}1t=c.4l/Q||1;1s=c.4k/M||1;9(K.a!=3q){23(K.a,K.b,K.j,K.g);K.2F=!K.1r}9(K.1T){c.1T=$.2c({2b:1,2a:"19"},K.1T)}B.29(c.1S+"-4j");1k.29(c.1S+"-4i");3p(i=0;i++<4;){$(I[i-1]).29(c.1S+"-2J"+i)}1R(1k,{4h:"2I-28",4g:"1e"});1R(I,{3o:"1e",2K:"2J-H"});1R(B,{4f:"2I-28",4e:"1e"});9(o=c.3n){$(I[0]).q({2H:"3m",3k:o})}9(o=c.3l){$(I[1]).q({2H:"4d",3k:o})}A.2G(1k.r(I).r(1K)).2G(E);9(1j){9(o=(B.q("3j")||"").3i(/1e=(\\d+)/)){B.q("1e",o[1]/1Z)}9(o=(I.q("3j")||"").3i(/1e=(\\d+)/)){I.q("1e",o[1]/1Z)}}9(K.1r){27(A.r(B))}X{9(K.2F&&1F){1Q=11;A.r(B).2E(c.1P||0);22()}}14=(d=(c.4c||"").4b(/:/))[0]/d[1];O.r(B).U("1O",2A);9(c.1E||c.1D===Y){A.U("P",1d).U("1O",2C);$(3h).U("19",2B)}X{9(c.1D||c.1E===Y){9(c.2D||c.26){A.P(1d).1O(2C)}$(3h).19(2B)}9(!c.4a){O.r(B).1O(2A)}}c.1D=c.1E=1Y};J.1o=m(){25({1E:11});A.r(B).1o()};J.49=m(){C c};J.33=25;J.48=13;J.47=23;J.46=1N;J.45=22;18 1j=(/44 ([\\w.]+)/i.43(1M)||[])[1],3c=/42/i.1c(1M),3d=/41/i.1c(1M)&&!/3Z/i.1c(1M);$p=O;3g($p.3f){12=D(12,!1L($p.q("z-3e"))?$p.q("z-3e"):12);9($p.q("1p")=="21"){1J="21"}$p=$p.20(":3Y(1q)")}12=c.1I||12;9(1j){O.3X("3W","3V")}$.N.2z=1j||3d?"3U":"3T";9(3c){1K=V().q({H:"1Z%",L:"1Z%",1p:"1H",1I:12+2||2})}A.r(B).q({3b:"3a",1p:1J,3S:"3a",1I:12||"0"});A.q({1I:12+2||2});1k.r(I).q({1p:"1H",36:0});T.35||T.3R=="35"||!O.2y("3Q")?2x():O.1G("3P",2x);9(!1F&&1j&&1j>=7){T.34=T.34}};$.2w.N=m(Z){Z=Z||{};J.3O(m(){9($(J).1C("N")){9(Z.1o){$(J).1C("N").1o();$(J).3N("N")}X{$(J).1C("N").33(Z)}}X{9(!Z.1o){9(Z.1D===1Y&&Z.1E===1Y){Z.1D=11}$(J).1C("N",3M $.N(J,Z))}}});9(Z.3L){C $(J).1C("N")}C J}})(3K);',62,304,'|||||||||if|x1|y1|_7|||_23|y2|||x2||top|function||||css|add|||_4|left|||||_a|_d|return|_2|_e|_3|_10|width|_c|this|_55|height|_13|imgAreaSelect|_8|mousemove|_12|document|_1c|_6|unbind|_5|_1|else|false|_58||true|_16|_2c|_21|case|_50|_11|var|resize|_29|_28|test|_3a|opacity|_30|_15|sy|sx|_35|_b|_14|_27|_26|remove|position|body|hide|_1b|_1a|break|_45|_42|mouseup|evY|evX|_1e|_1d|data|enable|disable|_9|one|absolute|zIndex|_17|_f|isNaN|ua|_4a|mousedown|fadeSpeed|_22|_51|classPrefix|keys|_31|_32|resizeMargin|_40|undefined|100|parent|fixed|_36|_2e||_4f|movable|_38|color|addClass|ctrl|shift|extend|_54|altKey|onSelectEnd|onSelectChange|_49|_4c|_19|_18|_3e|_48|_20|_1f|_25|outerWidth|scrollTop|scrollLeft|offset|_24|Math|fn|_4e|is|keyPress|_4b|_4d|_3f|resizable|fadeIn|show|append|borderStyle|background|border|borderWidth|handles|_53|key|switch|alt|arrows|_34|_3c|_41|_44|cursor|_3b|_39|innerWidth|onKeyPress|outerHeight|_2f|_2d|setOptions|src|complete|fontSize||||hidden|visibility|_56|_57|index|length|while|window|match|filter|borderColor|borderColor2|solid|borderColor1|borderOpacity|for|null|_52|default|originalEvent|ctrlKey|shiftKey|onInit|setTimeout|onSelectStart|which|_47|_46|_43|_37|margin|_33|slice|innerHeight|_2b|_2a|jQuery|instance|new|removeData|each|load|img|readyState|overflow|keypress|keydown|on|unselectable|attr|not|chrome||webkit|opera|exec|msie|update|cancelSelection|setSelection|getSelection|getOptions|persistent|split|aspectRatio|dashed|outerOpacity|outerColor|selectionOpacity|selectionColor|selection|outer|imageHeight|imageWidth|parseInt|handle|corners|in|keyCode|imgareaselect|animated|instanceof|visible|preventDefault|autoHide|_3d|toggle|move|mouseout|fadeOut|auto|relative|getBoundingClientRect|jquery|maxHeight|maxWidth|minHeight|minWidth|pageY|pageX|userAgent|navigator|documentElement|div|round|min|max|abs'.split('|'))) 2 | --------------------------------------------------------------------------------