diff --git a/.gitignore b/.gitignore
index 3f2ebf8ce386ea0bf49af91dca00f2043fc394fb..80e52bf5be754892bd0e7cf898fb347e9801b1cf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,16 +2,17 @@
/thinkphp/
/vendor/
/runtime/*
-/addons/*
-/application/admin/command/Install/*.lock
-/public/assets/libs/
+#/addons/*
+#/application/admin/command/Install/*.lock
+#/public/assets/libs/
/public/assets/addons/*
/public/uploads/*
.idea
-composer.lock
+#composer.lock
*.log
*.css.map
!.gitkeep
.env
.svn
.vscode
+.Ds_Store
diff --git a/addons/alioss/Alioss.php b/addons/alioss/Alioss.php
new file mode 100644
index 0000000000000000000000000000000000000000..161e4d0db46a6eeaab9ffb4f146b78270fbeebf0
--- /dev/null
+++ b/addons/alioss/Alioss.php
@@ -0,0 +1,96 @@
+getConfig();
+ if ($config['uploadmode'] === 'client') {
+ $upload = [
+ 'cdnurl' => $config['cdnurl'],
+ 'uploadurl' => 'https://' . $config['bucket'] . '.' . $config['endpoint'],
+ 'bucket' => $config['bucket'],
+ 'maxsize' => $config['maxsize'],
+ 'mimetype' => $config['mimetype'],
+ 'multipart' => [],
+ 'multiple' => $config['multiple'] ? true : false,
+ 'storage' => 'alioss'
+ ];
+ } else {
+ $upload = array_merge($upload, [
+ 'cdnurl' => $config['cdnurl'],
+ 'uploadurl' => addon_url('alioss/index/upload'),
+ 'maxsize' => $config['maxsize'],
+ 'mimetype' => $config['mimetype'],
+ 'multiple' => $config['multiple'] ? true : false,
+ ]);
+ }
+ }
+
+ /**
+ * 附件删除后
+ */
+ public function uploadDelete($attachment)
+ {
+ $config = $this->getConfig();
+ if ($attachment['storage'] == 'alioss' && isset($config['syncdelete']) && $config['syncdelete']) {
+ $endpoint = "http://" . $config['endpoint'];
+ try {
+ $ossClient = new OssClient($config['app_id'], $config['app_key'], $endpoint);
+ $ossClient->deleteObject($config['bucket'], ltrim($attachment->url, '/'));
+ } catch (OssException $e) {
+ return false;
+ }
+ //如果是服务端中转,还需要删除本地文件
+ if ($config['uploadmode'] == 'server') {
+ $filePath = ROOT_PATH . 'public' . str_replace('/', DS, $attachment->url);
+ if ($filePath) {
+ @unlink($filePath);
+ }
+ }
+ }
+ return true;
+ }
+
+}
diff --git a/addons/alioss/__MACOSX/._Alioss.php b/addons/alioss/__MACOSX/._Alioss.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/._Alioss.php differ
diff --git a/addons/alioss/__MACOSX/._assets b/addons/alioss/__MACOSX/._assets
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/._assets differ
diff --git a/addons/alioss/__MACOSX/._bootstrap.js b/addons/alioss/__MACOSX/._bootstrap.js
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/._bootstrap.js differ
diff --git a/addons/alioss/__MACOSX/._config.php b/addons/alioss/__MACOSX/._config.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/._config.php differ
diff --git a/addons/alioss/__MACOSX/._controller b/addons/alioss/__MACOSX/._controller
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/._controller differ
diff --git a/addons/alioss/__MACOSX/._info.ini b/addons/alioss/__MACOSX/._info.ini
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/._info.ini differ
diff --git a/addons/alioss/__MACOSX/._library b/addons/alioss/__MACOSX/._library
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/._library differ
diff --git a/addons/alioss/__MACOSX/assets/._js b/addons/alioss/__MACOSX/assets/._js
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/assets/._js differ
diff --git a/addons/alioss/__MACOSX/assets/js/._spark.js b/addons/alioss/__MACOSX/assets/js/._spark.js
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/assets/js/._spark.js differ
diff --git a/addons/alioss/__MACOSX/controller/._Index.php b/addons/alioss/__MACOSX/controller/._Index.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/controller/._Index.php differ
diff --git a/addons/alioss/__MACOSX/library/._Auth.php b/addons/alioss/__MACOSX/library/._Auth.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/._Auth.php differ
diff --git a/addons/alioss/__MACOSX/library/._OSS b/addons/alioss/__MACOSX/library/._OSS
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/._OSS differ
diff --git a/addons/alioss/__MACOSX/library/OSS/._Core b/addons/alioss/__MACOSX/library/OSS/._Core
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/._Core differ
diff --git a/addons/alioss/__MACOSX/library/OSS/._Http b/addons/alioss/__MACOSX/library/OSS/._Http
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/._Http differ
diff --git a/addons/alioss/__MACOSX/library/OSS/._Model b/addons/alioss/__MACOSX/library/OSS/._Model
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/._Model differ
diff --git a/addons/alioss/__MACOSX/library/OSS/._OssClient.php b/addons/alioss/__MACOSX/library/OSS/._OssClient.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/._OssClient.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/._Result b/addons/alioss/__MACOSX/library/OSS/._Result
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/._Result differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Core/._MimeTypes.php b/addons/alioss/__MACOSX/library/OSS/Core/._MimeTypes.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Core/._MimeTypes.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Core/._OssException.php b/addons/alioss/__MACOSX/library/OSS/Core/._OssException.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Core/._OssException.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Core/._OssUtil.php b/addons/alioss/__MACOSX/library/OSS/Core/._OssUtil.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Core/._OssUtil.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Http/._LICENSE b/addons/alioss/__MACOSX/library/OSS/Http/._LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Http/._LICENSE differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Http/._RequestCore.php b/addons/alioss/__MACOSX/library/OSS/Http/._RequestCore.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Http/._RequestCore.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Http/._RequestCore_Exception.php b/addons/alioss/__MACOSX/library/OSS/Http/._RequestCore_Exception.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Http/._RequestCore_Exception.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Http/._ResponseCore.php b/addons/alioss/__MACOSX/library/OSS/Http/._ResponseCore.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Http/._ResponseCore.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._BucketInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._BucketInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._BucketInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._BucketListInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._BucketListInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._BucketListInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._CnameConfig.php b/addons/alioss/__MACOSX/library/OSS/Model/._CnameConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._CnameConfig.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._CorsConfig.php b/addons/alioss/__MACOSX/library/OSS/Model/._CorsConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._CorsConfig.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._CorsRule.php b/addons/alioss/__MACOSX/library/OSS/Model/._CorsRule.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._CorsRule.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._GetLiveChannelHistory.php b/addons/alioss/__MACOSX/library/OSS/Model/._GetLiveChannelHistory.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._GetLiveChannelHistory.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._GetLiveChannelInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._GetLiveChannelInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._GetLiveChannelInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._GetLiveChannelStatus.php b/addons/alioss/__MACOSX/library/OSS/Model/._GetLiveChannelStatus.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._GetLiveChannelStatus.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._LifecycleAction.php b/addons/alioss/__MACOSX/library/OSS/Model/._LifecycleAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._LifecycleAction.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._LifecycleConfig.php b/addons/alioss/__MACOSX/library/OSS/Model/._LifecycleConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._LifecycleConfig.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._LifecycleRule.php b/addons/alioss/__MACOSX/library/OSS/Model/._LifecycleRule.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._LifecycleRule.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._ListMultipartUploadInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._ListMultipartUploadInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._ListMultipartUploadInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._ListPartsInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._ListPartsInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._ListPartsInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelConfig.php b/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelConfig.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelHistory.php b/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelHistory.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelHistory.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelListInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelListInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._LiveChannelListInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._LoggingConfig.php b/addons/alioss/__MACOSX/library/OSS/Model/._LoggingConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._LoggingConfig.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._ObjectInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._ObjectInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._ObjectInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._ObjectListInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._ObjectListInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._ObjectListInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._PartInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._PartInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._PartInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._PrefixInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._PrefixInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._PrefixInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._RefererConfig.php b/addons/alioss/__MACOSX/library/OSS/Model/._RefererConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._RefererConfig.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._StorageCapacityConfig.php b/addons/alioss/__MACOSX/library/OSS/Model/._StorageCapacityConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._StorageCapacityConfig.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._UploadInfo.php b/addons/alioss/__MACOSX/library/OSS/Model/._UploadInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._UploadInfo.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._WebsiteConfig.php b/addons/alioss/__MACOSX/library/OSS/Model/._WebsiteConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._WebsiteConfig.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Model/._XmlConfig.php b/addons/alioss/__MACOSX/library/OSS/Model/._XmlConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Model/._XmlConfig.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._AclResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._AclResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._AclResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._AppendResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._AppendResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._AppendResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._BodyResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._BodyResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._BodyResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._CallbackResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._CallbackResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._CallbackResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._CopyObjectResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._CopyObjectResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._CopyObjectResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._DeleteObjectsResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._DeleteObjectsResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._DeleteObjectsResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._ExistResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._ExistResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._ExistResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetCnameResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetCnameResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetCnameResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetCorsResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetCorsResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetCorsResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetLifecycleResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetLifecycleResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetLifecycleResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetLiveChannelHistoryResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetLiveChannelHistoryResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetLiveChannelHistoryResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetLiveChannelInfoResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetLiveChannelInfoResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetLiveChannelInfoResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetLiveChannelStatusResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetLiveChannelStatusResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetLiveChannelStatusResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetLocationResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetLocationResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetLocationResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetLoggingResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetLoggingResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetLoggingResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetRefererResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetRefererResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetRefererResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetStorageCapacityResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetStorageCapacityResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetStorageCapacityResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._GetWebsiteResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._GetWebsiteResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._GetWebsiteResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._HeaderResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._HeaderResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._HeaderResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._InitiateMultipartUploadResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._InitiateMultipartUploadResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._InitiateMultipartUploadResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._ListBucketsResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._ListBucketsResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._ListBucketsResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._ListLiveChannelResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._ListLiveChannelResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._ListLiveChannelResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._ListMultipartUploadResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._ListMultipartUploadResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._ListMultipartUploadResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._ListObjectsResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._ListObjectsResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._ListObjectsResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._ListPartsResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._ListPartsResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._ListPartsResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._PutLiveChannelResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._PutLiveChannelResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._PutLiveChannelResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._PutSetDeleteResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._PutSetDeleteResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._PutSetDeleteResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._Result.php b/addons/alioss/__MACOSX/library/OSS/Result/._Result.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._Result.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._SymlinkResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._SymlinkResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._SymlinkResult.php differ
diff --git a/addons/alioss/__MACOSX/library/OSS/Result/._UploadPartResult.php b/addons/alioss/__MACOSX/library/OSS/Result/._UploadPartResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..04c39370dde3b2365e34cc8bc2b998361edf965a
Binary files /dev/null and b/addons/alioss/__MACOSX/library/OSS/Result/._UploadPartResult.php differ
diff --git a/addons/alioss/assets/js/spark.js b/addons/alioss/assets/js/spark.js
new file mode 100644
index 0000000000000000000000000000000000000000..5a22f703dcaaae60b2b165bee5031e72f42f2c58
--- /dev/null
+++ b/addons/alioss/assets/js/spark.js
@@ -0,0 +1 @@
+(function(factory){if(typeof exports==="object"){module.exports=factory()}else if(typeof define==="function"&&define.amd){define(factory)}else{var glob;try{glob=window}catch(e){glob=self}glob.SparkMD5=factory()}})(function(undefined){"use strict";var add32=function(a,b){return a+b&4294967295},hex_chr=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];function cmn(q,a,b,x,s,t){a=add32(add32(a,q),add32(x,t));return add32(a<>>32-s,b)}function md5cycle(x,k){var a=x[0],b=x[1],c=x[2],d=x[3];a+=(b&c|~b&d)+k[0]-680876936|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[1]-389564586|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[2]+606105819|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[3]-1044525330|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[4]-176418897|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[5]+1200080426|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[6]-1473231341|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[7]-45705983|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[8]+1770035416|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[9]-1958414417|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[10]-42063|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[11]-1990404162|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[12]+1804603682|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[13]-40341101|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[14]-1502002290|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[15]+1236535329|0;b=(b<<22|b>>>10)+c|0;a+=(b&d|c&~d)+k[1]-165796510|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[6]-1069501632|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[11]+643717713|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[0]-373897302|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[5]-701558691|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[10]+38016083|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[15]-660478335|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[4]-405537848|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[9]+568446438|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[14]-1019803690|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[3]-187363961|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[8]+1163531501|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[13]-1444681467|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[2]-51403784|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[7]+1735328473|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[12]-1926607734|0;b=(b<<20|b>>>12)+c|0;a+=(b^c^d)+k[5]-378558|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[8]-2022574463|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[11]+1839030562|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[14]-35309556|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[1]-1530992060|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[4]+1272893353|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[7]-155497632|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[10]-1094730640|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[13]+681279174|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[0]-358537222|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[3]-722521979|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[6]+76029189|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[9]-640364487|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[12]-421815835|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[15]+530742520|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[2]-995338651|0;b=(b<<23|b>>>9)+c|0;a+=(c^(b|~d))+k[0]-198630844|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[7]+1126891415|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[14]-1416354905|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[5]-57434055|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[12]+1700485571|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[3]-1894986606|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[10]-1051523|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[1]-2054922799|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[8]+1873313359|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[15]-30611744|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[6]-1560198380|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[13]+1309151649|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[4]-145523070|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[11]-1120210379|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[2]+718787259|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[9]-343485551|0;b=(b<<21|b>>>11)+c|0;x[0]=a+x[0]|0;x[1]=b+x[1]|0;x[2]=c+x[2]|0;x[3]=d+x[3]|0}function md5blk(s){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=s.charCodeAt(i)+(s.charCodeAt(i+1)<<8)+(s.charCodeAt(i+2)<<16)+(s.charCodeAt(i+3)<<24)}return md5blks}function md5blk_array(a){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=a[i]+(a[i+1]<<8)+(a[i+2]<<16)+(a[i+3]<<24)}return md5blks}function md51(s){var n=s.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk(s.substring(i-64,i)))}s=s.substring(i-64);length=s.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i>2]|=s.charCodeAt(i)<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function md51_array(a){var n=a.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk_array(a.subarray(i-64,i)))}a=i-64>2]|=a[i]<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function rhex(n){var s="",j;for(j=0;j<4;j+=1){s+=hex_chr[n>>j*8+4&15]+hex_chr[n>>j*8&15]}return s}function hex(x){var i;for(i=0;i>16)+(y>>16)+(lsw>>16);return msw<<16|lsw&65535}}if(typeof ArrayBuffer!=="undefined"&&!ArrayBuffer.prototype.slice){(function(){function clamp(val,length){val=val|0||0;if(val<0){return Math.max(val+length,0)}return Math.min(val,length)}ArrayBuffer.prototype.slice=function(from,to){var length=this.byteLength,begin=clamp(from,length),end=length,num,target,targetArray,sourceArray;if(to!==undefined){end=clamp(to,length)}if(begin>end){return new ArrayBuffer(0)}num=end-begin;target=new ArrayBuffer(num);targetArray=new Uint8Array(target);sourceArray=new Uint8Array(this,begin,num);targetArray.set(sourceArray);return target}})()}function toUtf8(str){if(/[\u0080-\uFFFF]/.test(str)){str=unescape(encodeURIComponent(str))}return str}function utf8Str2ArrayBuffer(str,returnUInt8Array){var length=str.length,buff=new ArrayBuffer(length),arr=new Uint8Array(buff),i;for(i=0;i>2]|=buff.charCodeAt(i)<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.prototype.reset=function(){this._buff="";this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.prototype.getState=function(){return{buff:this._buff,length:this._length,hash:this._hash}};SparkMD5.prototype.setState=function(state){this._buff=state.buff;this._length=state.length;this._hash=state.hash;return this};SparkMD5.prototype.destroy=function(){delete this._hash;delete this._buff;delete this._length};SparkMD5.prototype._finish=function(tail,length){var i=length,tmp,lo,hi;tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(this._hash,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=this._length*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(this._hash,tail)};SparkMD5.hash=function(str,raw){return SparkMD5.hashBinary(toUtf8(str),raw)};SparkMD5.hashBinary=function(content,raw){var hash=md51(content),ret=hex(hash);return raw?hexToBinaryString(ret):ret};SparkMD5.ArrayBuffer=function(){this.reset()};SparkMD5.ArrayBuffer.prototype.append=function(arr){var buff=concatenateArrayBuffers(this._buff.buffer,arr,true),length=buff.length,i;this._length+=arr.byteLength;for(i=64;i<=length;i+=64){md5cycle(this._hash,md5blk_array(buff.subarray(i-64,i)))}this._buff=i-64>2]|=buff[i]<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.ArrayBuffer.prototype.reset=function(){this._buff=new Uint8Array(0);this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.ArrayBuffer.prototype.getState=function(){var state=SparkMD5.prototype.getState.call(this);state.buff=arrayBuffer2Utf8Str(state.buff);return state};SparkMD5.ArrayBuffer.prototype.setState=function(state){state.buff=utf8Str2ArrayBuffer(state.buff,true);return SparkMD5.prototype.setState.call(this,state)};SparkMD5.ArrayBuffer.prototype.destroy=SparkMD5.prototype.destroy;SparkMD5.ArrayBuffer.prototype._finish=SparkMD5.prototype._finish;SparkMD5.ArrayBuffer.hash=function(arr,raw){var hash=md51_array(new Uint8Array(arr)),ret=hex(hash);return raw?hexToBinaryString(ret):ret};return SparkMD5});
diff --git a/addons/alioss/bootstrap.js b/addons/alioss/bootstrap.js
new file mode 100644
index 0000000000000000000000000000000000000000..bbafc44856e38cae25f560fa74980682eebfd7aa
--- /dev/null
+++ b/addons/alioss/bootstrap.js
@@ -0,0 +1,104 @@
+//如果开启了alioss客户端上传模式
+if (typeof Config.upload.storage !== 'undefined' && Config.upload.storage === 'alioss') {
+ require(['upload', '../addons/alioss/js/spark'], function (Upload, SparkMD5) {
+ var _onFileAdded = Upload.events.onFileAdded;
+ var _onUploadResponse = Upload.events.onUploadResponse;
+ var getFileMd5 = function (file, cb) {
+ var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
+ file = file.getNative(),
+ chunkSize = 2097152, // Read in chunks of 2MB
+ chunks = Math.ceil(file.size / chunkSize),
+ currentChunk = 0,
+ spark = new SparkMD5.ArrayBuffer(),
+ fileReader = new FileReader();
+
+ fileReader.onload = function (e) {
+ spark.append(e.target.result); // Append array buffer
+ currentChunk++;
+ if (currentChunk < chunks) {
+ loadNext();
+ } else {
+ cb && cb(spark.end()); // Compute hash
+ }
+ };
+
+ fileReader.onerror = function () {
+ console.warn('oops, something went wrong.');
+ };
+
+ function loadNext() {
+ var start = currentChunk * chunkSize,
+ end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
+
+ fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
+ }
+
+ loadNext();
+ };
+ var _process = function (up, file) {
+ (function (up, file) {
+ getFileMd5(file, function (md5) {
+ Fast.api.ajax({
+ url: "/addons/alioss/index/params",
+ data: {method: 'POST', md5: md5, name: file.name, type: file.type, size: file.size},
+ }, function (data) {
+ file.md5 = md5;
+ file.status = 1;
+ file.key = data.key;
+ file.OSSAccessKeyId = data.id;
+ file.policy = data.policy;
+ file.signature = data.signature;
+ up.start();
+ return false;
+ });
+ });
+ })(up, file);
+ };
+ Upload.events.onFileAdded = function (up, files) {
+ return _onFileAdded.call(this, up, files);
+ };
+ Upload.events.onBeforeUpload = function (up, file) {
+ if (typeof file.md5 === 'undefined') {
+ up.stop();
+ _process(up, file);
+ } else {
+ up.settings.headers = up.settings.headers || {};
+ up.settings.multipart_params.key = file.key;
+ up.settings.multipart_params.OSSAccessKeyId = file.OSSAccessKeyId;
+ up.settings.multipart_params.success_action_status = 200;
+ if (typeof file.callback !== 'undefined') {
+ up.settings.multipart_params.callback = file.callback;
+ }
+ up.settings.multipart_params.policy = file.policy;
+ up.settings.multipart_params.signature = file.signature;
+ //up.settings.send_file_name = false;
+ }
+ };
+ Upload.events.onUploadResponse = function (response, info, up, file) {
+ try {
+ var ret = {};
+ if (info.status === 200) {
+ var url = '/' + file.key;
+ Fast.api.ajax({
+ url: "/addons/alioss/index/notify",
+ data: {method: 'POST', name: file.name, url: url, md5: file.md5, size: file.size, type: file.type, policy: file.policy, signature: file.signature}
+ }, function () {
+ return false;
+ });
+ ret.code = 1;
+ ret.data = {
+ url: url
+ };
+ } else {
+ ret.code = 0;
+ ret.msg = info.response;
+ }
+ return _onUploadResponse.call(this, JSON.stringify(ret));
+
+ } catch (e) {
+ }
+ return _onUploadResponse.call(this, response);
+
+ };
+ });
+}
\ No newline at end of file
diff --git a/addons/alioss/config.php b/addons/alioss/config.php
new file mode 100644
index 0000000000000000000000000000000000000000..9f0a5a63d4ea3c1ad1895caebba64814a3b4d71e
--- /dev/null
+++ b/addons/alioss/config.php
@@ -0,0 +1,176 @@
+ 'app_id',
+ 'title' => 'app_id',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'your app id',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'app_key',
+ 'title' => 'app_key',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'your app key',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'bucket',
+ 'title' => 'Bucket',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'yourbucket',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '阿里云OSS的空间名',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'endpoint',
+ 'title' => 'EndPoint',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'oss-cn-shenzhen.aliyuncs.com',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '如果是服务器中转模式,可填写内网域名,前面不可加http://',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'cdnurl',
+ 'title' => 'CDN地址',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'http://yourbucket.oss-cn-shenzhen.aliyuncs.com',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '请填写CDN地址,必须以http://开头',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'uploadmode',
+ 'title' => '上传模式',
+ 'type' => 'select',
+ 'content' =>
+ array(
+ 'client' => '客户端直传(速度快,无备份)',
+ 'server' => '服务器中转(占用服务器带宽,有备份)',
+ ),
+ 'value' => 'server',
+ 'rule' => '',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'savekey',
+ 'title' => '保存文件名',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => '/uploads/{year}{mon}{day}/{filemd5}{.suffix}',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'expire',
+ 'title' => '上传有效时长',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => '600',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'maxsize',
+ 'title' => '最大可上传',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => '10M',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'mimetype',
+ 'title' => '可上传后缀格式',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => '*',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'multiple',
+ 'title' => '多文件上传',
+ 'type' => 'bool',
+ 'content' =>
+ array(),
+ 'value' => '0',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'syncdelete',
+ 'title' => '附件删除时是否同步删除文件',
+ 'type' => 'bool',
+ 'content' =>
+ array(),
+ 'value' => '0',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => '__tips__',
+ 'title' => '温馨提示',
+ 'type' => '',
+ 'content' =>
+ array(),
+ 'value' => '在使用之前请注册阿里云账号并进行认证和创建空间,注册链接:https://oss.console.aliyun.com/index FastAdmin赠送你阿里云最高1888云产品通用代金券,如有需要可以点击领取 ',
+ 'rule' => '',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+);
diff --git a/addons/alioss/controller/Index.php b/addons/alioss/controller/Index.php
new file mode 100644
index 0000000000000000000000000000000000000000..14f59442c36188b29149f85abddfbdbe40107c2d
--- /dev/null
+++ b/addons/alioss/controller/Index.php
@@ -0,0 +1,188 @@
+error("当前插件暂无前台页面");
+ }
+
+ /**
+ * 获取签名
+ */
+ public function params()
+ {
+ Config::set('default_return_type', 'json');
+
+ $name = $this->request->post('name');
+ $md5 = $this->request->post('md5');
+ $auth = new \addons\alioss\library\Auth();
+ $params = $auth->params($name, $md5);
+ $this->success('', null, $params);
+ return;
+ }
+
+ /**
+ * 服务器中转上传文件
+ */
+ public function upload()
+ {
+ Config::set('default_return_type', 'json');
+ if (!session('admin') && !$this->auth->id) {
+ $this->error("请登录后再进行操作");
+ }
+ $config = get_addon_config('alioss');
+
+ $endpoint = "http://" . $config['endpoint'];
+
+ $file = $this->request->file('file');
+ if (!$file || !$file->isValid()) {
+ $this->error("请上传有效的文件");
+ }
+ $fileInfo = $file->getInfo();
+
+ $filePath = $file->getRealPath() ?: $file->getPathname();
+
+ preg_match('/(\d+)(\w+)/', $config['maxsize'], $matches);
+ $type = strtolower($matches[2]);
+ $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
+ $size = (int)$config['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
+
+ $suffix = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
+ $suffix = $suffix ? $suffix : 'file';
+
+ $md5 = md5_file($filePath);
+ $search = ['{year}', '{mon}', '{month}', '{day}', '{filemd5}', '{suffix}', '{.suffix}'];
+ $replace = [date("Y"), date("m"), date("m"), date("d"), $md5, $suffix, '.' . $suffix];
+ $object = ltrim(str_replace($search, $replace, $config['savekey']), '/');
+
+ $mimetypeArr = explode(',', strtolower($config['mimetype']));
+ $typeArr = explode('/', $fileInfo['type']);
+
+ //检查文件大小
+ if (!$file->checkSize($size)) {
+ $this->error("起过最大可上传文件限制");
+ }
+
+ //验证文件后缀
+ if ($config['mimetype'] !== '*' &&
+ (
+ !in_array($suffix, $mimetypeArr)
+ || (stripos($typeArr[0] . '/', $config['mimetype']) !== false && (!in_array($fileInfo['type'], $mimetypeArr) && !in_array($typeArr[0] . '/*', $mimetypeArr)))
+ )
+ ) {
+ $this->error(__('上传格式限制'));
+ }
+
+ $savekey = '/' . $object;
+
+ $uploadDir = substr($savekey, 0, strripos($savekey, '/') + 1);
+ $fileName = substr($savekey, strripos($savekey, '/') + 1);
+ //先上传到本地
+ $splInfo = $file->move(ROOT_PATH . '/public' . $uploadDir, $fileName);
+ if ($splInfo) {
+ $extparam = $this->request->post();
+ $filePath = $splInfo->getRealPath() ?: $splInfo->getPathname();
+
+ $sha1 = sha1_file($filePath);
+ $imagewidth = $imageheight = 0;
+ if (in_array($suffix, ['gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf'])) {
+ $imgInfo = getimagesize($splInfo->getPathname());
+ $imagewidth = isset($imgInfo[0]) ? $imgInfo[0] : $imagewidth;
+ $imageheight = isset($imgInfo[1]) ? $imgInfo[1] : $imageheight;
+ }
+ $params = array(
+ 'admin_id' => session('admin.id'),
+ 'user_id' => $this->auth->id,
+ 'filesize' => $fileInfo['size'],
+ 'imagewidth' => $imagewidth,
+ 'imageheight' => $imageheight,
+ 'imagetype' => $suffix,
+ 'imageframes' => 0,
+ 'mimetype' => $fileInfo['type'],
+ 'url' => $uploadDir . $splInfo->getSaveName(),
+ 'uploadtime' => time(),
+ 'storage' => 'local',
+ 'sha1' => $sha1,
+ 'extparam' => json_encode($extparam),
+ );
+ $attachment = new Attachment;
+ $attachment->data(array_filter($params));
+ $attachment->save();
+
+ //上传到远程
+ try {
+ $ossClient = new OssClient($config['app_id'], $config['app_key'], $endpoint);
+ $ossClient->uploadFile($config['bucket'], $object, $filePath);
+ } catch (OssException $e) {
+ $this->error('上传失败');
+ return;
+ }
+ $url = '/' . $object;
+
+ //上传成功后将存储变更为alioss
+ $attachment->storage = 'alioss';
+ $attachment->save();
+
+ $this->success("上传成功", null, ['url' => $url]);
+ } else {
+ $this->error('上传失败');
+ }
+ return;
+ }
+
+ /**
+ * 回调
+ */
+ public function notify()
+ {
+ Config::set('default_return_type', 'json');
+ $size = $this->request->post('size');
+ $name = $this->request->post('name');
+ $md5 = $this->request->post('md5');
+ $type = $this->request->post('type');
+ $signature = $this->request->post('signature');
+ $policy = $this->request->post('policy');
+ $url = $this->request->post('url');
+ $suffix = substr($name, stripos($name, '.') + 1);
+ $auth = new \addons\alioss\library\Auth();
+ if ($auth->check($signature, $policy)) {
+ $attachment = Attachment::getBySha1($md5);
+ if (!$attachment) {
+ $params = array(
+ 'admin_id' => (int)session('admin.id'),
+ 'user_id' => (int)cookie('uid'),
+ 'filesize' => $size,
+ 'imagewidth' => 0,
+ 'imageheight' => 0,
+ 'imagetype' => $suffix,
+ 'imageframes' => 0,
+ 'mimetype' => $type,
+ 'url' => $url,
+ 'uploadtime' => time(),
+ 'storage' => 'alioss',
+ 'sha1' => $md5,
+ );
+ Attachment::create($params);
+ }
+ $this->success();
+ } else {
+ $this->error(__('You have no permission'));
+ }
+ return;
+ }
+
+}
diff --git a/addons/alioss/info.ini b/addons/alioss/info.ini
new file mode 100644
index 0000000000000000000000000000000000000000..6d53a1d381c9dc6b041ea78fd489eef45ca90aeb
--- /dev/null
+++ b/addons/alioss/info.ini
@@ -0,0 +1,8 @@
+name = alioss
+title = 阿里OSS上传
+intro = 使用阿里OSS存储,上传时直传阿里云OSS
+author = Karson
+website = http://www.fastadmin.net
+version = 1.0.3
+state = 1
+url = /fastadmin/my/public/addons/alioss
diff --git a/addons/alioss/library/Auth.php b/addons/alioss/library/Auth.php
new file mode 100644
index 0000000000000000000000000000000000000000..1235db2406f07c74b404b83013a09c4a22b3b74c
--- /dev/null
+++ b/addons/alioss/library/Auth.php
@@ -0,0 +1,78 @@
+ isset($config['notifyurl']) ? $config['notifyurl'] : '',
+ 'callbackBody' => 'filename=${object}&size=${size}&mimeType=${mimeType}&height=${imageInfo.height}&width=${imageInfo.width}',
+ 'callbackBodyType' => "application/x-www-form-urlencoded"
+ );
+
+ $base64_callback_body = base64_encode(json_encode($callback_param));
+
+ $now = time();
+ $end = $now + $config['expire']; //设置该policy超时时间是10s. 即这个policy过了这个有效时间,将不能访问
+ $expiration = $this->gmt_iso8601($end);
+
+ preg_match('/(\d+)(\w+)/', $config['maxsize'], $matches);
+ $type = strtolower($matches[2]);
+ $typeDict = ['b' => 0, 'k' => 1, 'kb' => 1, 'm' => 2, 'mb' => 2, 'gb' => 3, 'g' => 3];
+ $size = (int)$config['maxsize'] * pow(1024, isset($typeDict[$type]) ? $typeDict[$type] : 0);
+
+ //最大文件大小.用户可以自己设置
+ $condition = array(0 => 'content-length-range', 1 => 0, 2 => $size);
+ $conditions[] = $condition;
+
+ //表示用户上传的数据,必须是以$dir开始, 不然上传会失败,这一步不是必须项,只是为了安全起见,防止用户通过policy上传到别人的目录
+ //$start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
+ //$conditions[] = $start;
+
+ $arr = array('expiration' => $expiration, 'conditions' => $conditions);
+
+ $policy = base64_encode(json_encode($arr));
+ $signature = base64_encode(hash_hmac('sha1', $policy, $config['app_key'], true));
+
+ $suffix = substr($name, stripos($name, '.') + 1);
+ $search = ['{year}', '{mon}', '{month}', '{day}', '{filemd5}', '{suffix}', '{.suffix}'];
+ $replace = [date("Y"), date("m"), date("m"), date("d"), $md5, $suffix, '.' . $suffix];
+ $key = ltrim(str_replace($search, $replace, $config['savekey']), '/');
+
+ $response = array();
+ $response['id'] = $config['app_id'];
+ $response['key'] = $key;
+ $response['policy'] = $policy;
+ $response['signature'] = $signature;
+ $response['expire'] = $end;
+ $response['callback'] = '';
+ return $response;
+ }
+
+ public function check($signature, $policy)
+ {
+ $config = get_addon_config('alioss');
+ $sign = base64_encode(hash_hmac('sha1', $policy, $config['app_key'], true));
+ return $signature == $sign;
+ }
+
+ private function gmt_iso8601($time)
+ {
+ $dtStr = date("c", $time);
+ $mydatetime = new \DateTime($dtStr);
+ $expiration = $mydatetime->format(\DateTime::ISO8601);
+ $pos = strpos($expiration, '+');
+ $expiration = substr($expiration, 0, $pos);
+ return $expiration . "Z";
+ }
+
+}
diff --git a/addons/alioss/library/OSS/Core/MimeTypes.php b/addons/alioss/library/OSS/Core/MimeTypes.php
new file mode 100644
index 0000000000000000000000000000000000000000..e9b88ffa86b2fb11dd18fbe272e2461b6aba1d9f
--- /dev/null
+++ b/addons/alioss/library/OSS/Core/MimeTypes.php
@@ -0,0 +1,262 @@
+ 1) {
+ $ext = strtolower(end($parts));
+ if (isset(self::$mime_types[$ext])) {
+ return self::$mime_types[$ext];
+ }
+ }
+
+ return null;
+ }
+
+ private static $mime_types = array(
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
+ 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
+ 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
+ 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
+ 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
+ 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
+ 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
+ 'apk' => 'application/vnd.android.package-archive',
+ 'hqx' => 'application/mac-binhex40',
+ 'cpt' => 'application/mac-compactpro',
+ 'doc' => 'application/msword',
+ 'ogg' => 'audio/ogg',
+ 'pdf' => 'application/pdf',
+ 'rtf' => 'text/rtf',
+ 'mif' => 'application/vnd.mif',
+ 'xls' => 'application/vnd.ms-excel',
+ 'ppt' => 'application/vnd.ms-powerpoint',
+ 'odc' => 'application/vnd.oasis.opendocument.chart',
+ 'odb' => 'application/vnd.oasis.opendocument.database',
+ 'odf' => 'application/vnd.oasis.opendocument.formula',
+ 'odg' => 'application/vnd.oasis.opendocument.graphics',
+ 'otg' => 'application/vnd.oasis.opendocument.graphics-template',
+ 'odi' => 'application/vnd.oasis.opendocument.image',
+ 'odp' => 'application/vnd.oasis.opendocument.presentation',
+ 'otp' => 'application/vnd.oasis.opendocument.presentation-template',
+ 'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
+ 'ots' => 'application/vnd.oasis.opendocument.spreadsheet-template',
+ 'odt' => 'application/vnd.oasis.opendocument.text',
+ 'odm' => 'application/vnd.oasis.opendocument.text-master',
+ 'ott' => 'application/vnd.oasis.opendocument.text-template',
+ 'oth' => 'application/vnd.oasis.opendocument.text-web',
+ 'sxw' => 'application/vnd.sun.xml.writer',
+ 'stw' => 'application/vnd.sun.xml.writer.template',
+ 'sxc' => 'application/vnd.sun.xml.calc',
+ 'stc' => 'application/vnd.sun.xml.calc.template',
+ 'sxd' => 'application/vnd.sun.xml.draw',
+ 'std' => 'application/vnd.sun.xml.draw.template',
+ 'sxi' => 'application/vnd.sun.xml.impress',
+ 'sti' => 'application/vnd.sun.xml.impress.template',
+ 'sxg' => 'application/vnd.sun.xml.writer.global',
+ 'sxm' => 'application/vnd.sun.xml.math',
+ 'sis' => 'application/vnd.symbian.install',
+ 'wbxml' => 'application/vnd.wap.wbxml',
+ 'wmlc' => 'application/vnd.wap.wmlc',
+ 'wmlsc' => 'application/vnd.wap.wmlscriptc',
+ 'bcpio' => 'application/x-bcpio',
+ 'torrent' => 'application/x-bittorrent',
+ 'bz2' => 'application/x-bzip2',
+ 'vcd' => 'application/x-cdlink',
+ 'pgn' => 'application/x-chess-pgn',
+ 'cpio' => 'application/x-cpio',
+ 'csh' => 'application/x-csh',
+ 'dvi' => 'application/x-dvi',
+ 'spl' => 'application/x-futuresplash',
+ 'gtar' => 'application/x-gtar',
+ 'hdf' => 'application/x-hdf',
+ 'jar' => 'application/java-archive',
+ 'jnlp' => 'application/x-java-jnlp-file',
+ 'js' => 'application/javascript',
+ 'json' => 'application/json',
+ 'ksp' => 'application/x-kspread',
+ 'chrt' => 'application/x-kchart',
+ 'kil' => 'application/x-killustrator',
+ 'latex' => 'application/x-latex',
+ 'rpm' => 'application/x-rpm',
+ 'sh' => 'application/x-sh',
+ 'shar' => 'application/x-shar',
+ 'swf' => 'application/x-shockwave-flash',
+ 'sit' => 'application/x-stuffit',
+ 'sv4cpio' => 'application/x-sv4cpio',
+ 'sv4crc' => 'application/x-sv4crc',
+ 'tar' => 'application/x-tar',
+ 'tcl' => 'application/x-tcl',
+ 'tex' => 'application/x-tex',
+ 'man' => 'application/x-troff-man',
+ 'me' => 'application/x-troff-me',
+ 'ms' => 'application/x-troff-ms',
+ 'ustar' => 'application/x-ustar',
+ 'src' => 'application/x-wais-source',
+ 'zip' => 'application/zip',
+ 'm3u' => 'audio/x-mpegurl',
+ 'ra' => 'audio/x-pn-realaudio',
+ 'wav' => 'audio/x-wav',
+ 'wma' => 'audio/x-ms-wma',
+ 'wax' => 'audio/x-ms-wax',
+ 'pdb' => 'chemical/x-pdb',
+ 'xyz' => 'chemical/x-xyz',
+ 'bmp' => 'image/bmp',
+ 'gif' => 'image/gif',
+ 'ief' => 'image/ief',
+ 'png' => 'image/png',
+ 'wbmp' => 'image/vnd.wap.wbmp',
+ 'ras' => 'image/x-cmu-raster',
+ 'pnm' => 'image/x-portable-anymap',
+ 'pbm' => 'image/x-portable-bitmap',
+ 'pgm' => 'image/x-portable-graymap',
+ 'ppm' => 'image/x-portable-pixmap',
+ 'rgb' => 'image/x-rgb',
+ 'xbm' => 'image/x-xbitmap',
+ 'xpm' => 'image/x-xpixmap',
+ 'xwd' => 'image/x-xwindowdump',
+ 'css' => 'text/css',
+ 'rtx' => 'text/richtext',
+ 'tsv' => 'text/tab-separated-values',
+ 'jad' => 'text/vnd.sun.j2me.app-descriptor',
+ 'wml' => 'text/vnd.wap.wml',
+ 'wmls' => 'text/vnd.wap.wmlscript',
+ 'etx' => 'text/x-setext',
+ 'mxu' => 'video/vnd.mpegurl',
+ 'flv' => 'video/x-flv',
+ 'wm' => 'video/x-ms-wm',
+ 'wmv' => 'video/x-ms-wmv',
+ 'wmx' => 'video/x-ms-wmx',
+ 'wvx' => 'video/x-ms-wvx',
+ 'avi' => 'video/x-msvideo',
+ 'movie' => 'video/x-sgi-movie',
+ 'ice' => 'x-conference/x-cooltalk',
+ '3gp' => 'video/3gpp',
+ 'ai' => 'application/postscript',
+ 'aif' => 'audio/x-aiff',
+ 'aifc' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'asc' => 'text/plain',
+ 'atom' => 'application/atom+xml',
+ 'au' => 'audio/basic',
+ 'bin' => 'application/octet-stream',
+ 'cdf' => 'application/x-netcdf',
+ 'cgm' => 'image/cgm',
+ 'class' => 'application/octet-stream',
+ 'dcr' => 'application/x-director',
+ 'dif' => 'video/x-dv',
+ 'dir' => 'application/x-director',
+ 'djv' => 'image/vnd.djvu',
+ 'djvu' => 'image/vnd.djvu',
+ 'dll' => 'application/octet-stream',
+ 'dmg' => 'application/octet-stream',
+ 'dms' => 'application/octet-stream',
+ 'dtd' => 'application/xml-dtd',
+ 'dv' => 'video/x-dv',
+ 'dxr' => 'application/x-director',
+ 'eps' => 'application/postscript',
+ 'exe' => 'application/octet-stream',
+ 'ez' => 'application/andrew-inset',
+ 'gram' => 'application/srgs',
+ 'grxml' => 'application/srgs+xml',
+ 'gz' => 'application/x-gzip',
+ 'htm' => 'text/html',
+ 'html' => 'text/html',
+ 'ico' => 'image/x-icon',
+ 'ics' => 'text/calendar',
+ 'ifb' => 'text/calendar',
+ 'iges' => 'model/iges',
+ 'igs' => 'model/iges',
+ 'jp2' => 'image/jp2',
+ 'jpe' => 'image/jpeg',
+ 'jpeg' => 'image/jpeg',
+ 'jpg' => 'image/jpeg',
+ 'kar' => 'audio/midi',
+ 'lha' => 'application/octet-stream',
+ 'lzh' => 'application/octet-stream',
+ 'm4a' => 'audio/mp4a-latm',
+ 'm4p' => 'audio/mp4a-latm',
+ 'm4u' => 'video/vnd.mpegurl',
+ 'm4v' => 'video/x-m4v',
+ 'mac' => 'image/x-macpaint',
+ 'mathml' => 'application/mathml+xml',
+ 'mesh' => 'model/mesh',
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mov' => 'video/quicktime',
+ 'mp2' => 'audio/mpeg',
+ 'mp3' => 'audio/mpeg',
+ 'mp4' => 'video/mp4',
+ 'mpe' => 'video/mpeg',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpga' => 'audio/mpeg',
+ 'msh' => 'model/mesh',
+ 'nc' => 'application/x-netcdf',
+ 'oda' => 'application/oda',
+ 'ogv' => 'video/ogv',
+ 'pct' => 'image/pict',
+ 'pic' => 'image/pict',
+ 'pict' => 'image/pict',
+ 'pnt' => 'image/x-macpaint',
+ 'pntg' => 'image/x-macpaint',
+ 'ps' => 'application/postscript',
+ 'qt' => 'video/quicktime',
+ 'qti' => 'image/x-quicktime',
+ 'qtif' => 'image/x-quicktime',
+ 'ram' => 'audio/x-pn-realaudio',
+ 'rdf' => 'application/rdf+xml',
+ 'rm' => 'application/vnd.rn-realmedia',
+ 'roff' => 'application/x-troff',
+ 'sgm' => 'text/sgml',
+ 'sgml' => 'text/sgml',
+ 'silo' => 'model/mesh',
+ 'skd' => 'application/x-koan',
+ 'skm' => 'application/x-koan',
+ 'skp' => 'application/x-koan',
+ 'skt' => 'application/x-koan',
+ 'smi' => 'application/smil',
+ 'smil' => 'application/smil',
+ 'snd' => 'audio/basic',
+ 'so' => 'application/octet-stream',
+ 'svg' => 'image/svg+xml',
+ 't' => 'application/x-troff',
+ 'texi' => 'application/x-texinfo',
+ 'texinfo' => 'application/x-texinfo',
+ 'tif' => 'image/tiff',
+ 'tiff' => 'image/tiff',
+ 'tr' => 'application/x-troff',
+ 'txt' => 'text/plain',
+ 'vrml' => 'model/vrml',
+ 'vxml' => 'application/voicexml+xml',
+ 'webm' => 'video/webm',
+ 'webp' => 'image/webp',
+ 'wrl' => 'model/vrml',
+ 'xht' => 'application/xhtml+xml',
+ 'xhtml' => 'application/xhtml+xml',
+ 'xml' => 'application/xml',
+ 'xsl' => 'application/xml',
+ 'xslt' => 'application/xslt+xml',
+ 'xul' => 'application/vnd.mozilla.xul+xml',
+ );
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Core/OssException.php b/addons/alioss/library/OSS/Core/OssException.php
new file mode 100644
index 0000000000000000000000000000000000000000..b0e9e8b0d1e097d49e2aa34f039e948b308c5c27
--- /dev/null
+++ b/addons/alioss/library/OSS/Core/OssException.php
@@ -0,0 +1,54 @@
+details = $details;
+ } else {
+ $message = $details;
+ parent::__construct($message);
+ }
+ }
+
+ public function getHTTPStatus()
+ {
+ return isset($this->details['status']) ? $this->details['status'] : '';
+ }
+
+ public function getRequestId()
+ {
+ return isset($this->details['request-id']) ? $this->details['request-id'] : '';
+ }
+
+ public function getErrorCode()
+ {
+ return isset($this->details['code']) ? $this->details['code'] : '';
+ }
+
+ public function getErrorMessage()
+ {
+ return isset($this->details['message']) ? $this->details['message'] : '';
+ }
+
+ public function getDetails()
+ {
+ return isset($this->details['body']) ? $this->details['body'] : '';
+ }
+}
diff --git a/addons/alioss/library/OSS/Core/OssUtil.php b/addons/alioss/library/OSS/Core/OssUtil.php
new file mode 100644
index 0000000000000000000000000000000000000000..6e5d4133dcdbbbfbd3d80a14f090536a09f33947
--- /dev/null
+++ b/addons/alioss/library/OSS/Core/OssUtil.php
@@ -0,0 +1,461 @@
+ $value) {
+ if (is_string($key) && !is_array($value)) {
+ $temp[] = rawurlencode($key) . '=' . rawurlencode($value);
+ }
+ }
+ return implode('&', $temp);
+ }
+
+ /**
+ * 转义字符替换
+ *
+ * @param string $subject
+ * @return string
+ */
+ public static function sReplace($subject)
+ {
+ $search = array('<', '>', '&', '\'', '"');
+ $replace = array('<', '>', '&', ''', '"');
+ return str_replace($search, $replace, $subject);
+ }
+
+ /**
+ * 检查是否是中文编码
+ *
+ * @param $str
+ * @return int
+ */
+ public static function chkChinese($str)
+ {
+ return preg_match('/[\x80-\xff]./', $str);
+ }
+
+ /**
+ * 检测是否GB2312编码
+ *
+ * @param string $str
+ * @return boolean false UTF-8编码 TRUE GB2312编码
+ */
+ public static function isGb2312($str)
+ {
+ for ($i = 0; $i < strlen($str); $i++) {
+ $v = ord($str[$i]);
+ if ($v > 127) {
+ if (($v >= 228) && ($v <= 233)) {
+ if (($i + 2) >= (strlen($str) - 1)) return true; // not enough characters
+ $v1 = ord($str[$i + 1]);
+ $v2 = ord($str[$i + 2]);
+ if (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191))
+ return false;
+ else
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * 检测是否GBK编码
+ *
+ * @param string $str
+ * @param boolean $gbk
+ * @return boolean
+ */
+ public static function checkChar($str, $gbk = true)
+ {
+ for ($i = 0; $i < strlen($str); $i++) {
+ $v = ord($str[$i]);
+ if ($v > 127) {
+ if (($v >= 228) && ($v <= 233)) {
+ if (($i + 2) >= (strlen($str) - 1)) return $gbk ? true : FALSE; // not enough characters
+ $v1 = ord($str[$i + 1]);
+ $v2 = ord($str[$i + 2]);
+ if ($gbk) {
+ return (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) ? FALSE : TRUE;//GBK
+ } else {
+ return (($v1 >= 128) && ($v1 <= 191) && ($v2 >= 128) && ($v2 <= 191)) ? TRUE : FALSE;
+ }
+ }
+ }
+ }
+ return $gbk ? TRUE : FALSE;
+ }
+
+ /**
+ * 检验bucket名称是否合法
+ * bucket的命名规范:
+ * 1. 只能包括小写字母,数字
+ * 2. 必须以小写字母或者数字开头
+ * 3. 长度必须在3-63字节之间
+ *
+ * @param string $bucket Bucket名称
+ * @return boolean
+ */
+ public static function validateBucket($bucket)
+ {
+ $pattern = '/^[a-z0-9][a-z0-9-]{2,62}$/';
+ if (!preg_match($pattern, $bucket)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 检验object名称是否合法
+ * object命名规范:
+ * 1. 规则长度必须在1-1023字节之间
+ * 2. 使用UTF-8编码
+ * 3. 不能以 "/" "\\"开头
+ *
+ * @param string $object Object名称
+ * @return boolean
+ */
+ public static function validateObject($object)
+ {
+ $pattern = '/^.{1,1023}$/';
+ if (empty($object) || !preg_match($pattern, $object) ||
+ self::startsWith($object, '/') || self::startsWith($object, '\\')
+ ) {
+ return false;
+ }
+ return true;
+ }
+
+
+ /**
+ * 判断字符串$str是不是以$findMe开始
+ *
+ * @param string $str
+ * @param string $findMe
+ * @return bool
+ */
+ public static function startsWith($str, $findMe)
+ {
+ if (strpos($str, $findMe) === 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ /**
+ * 生成createBucketXmlBody接口的xml消息
+ *
+ * @param string $storageClass
+ * @return string
+ */
+ public static function createBucketXmlBody($storageClass)
+ {
+ $xml = new \SimpleXMLElement(' ');
+ $xml->addChild('StorageClass', $storageClass);
+ return $xml->asXML();
+ }
+
+ /**
+ * 检验$options
+ *
+ * @param array $options
+ * @throws OssException
+ * @return boolean
+ */
+ public static function validateOptions($options)
+ {
+ //$options
+ if ($options != NULL && !is_array($options)) {
+ throw new OssException ($options . ':' . 'option must be array');
+ }
+ }
+
+ /**
+ * 检查上传文件的内容是否合法
+ *
+ * @param $content string
+ * @throws OssException
+ */
+ public static function validateContent($content)
+ {
+ if (empty($content)) {
+ throw new OssException("http body content is invalid");
+ }
+ }
+
+ /**
+ * 校验BUCKET/OBJECT/OBJECT GROUP是否为空
+ *
+ * @param string $name
+ * @param string $errMsg
+ * @throws OssException
+ * @return void
+ */
+ public static function throwOssExceptionWithMessageIfEmpty($name, $errMsg)
+ {
+ if (empty($name)) {
+ throw new OssException($errMsg);
+ }
+ }
+
+ /**
+ * 仅供测试使用的接口,请勿使用
+ *
+ * @param $filename
+ * @param $size
+ */
+ public static function generateFile($filename, $size)
+ {
+ if (file_exists($filename) && $size == filesize($filename)) {
+ echo $filename . " already exists, no need to create again. ";
+ return;
+ }
+ $part_size = 1 * 1024 * 1024;
+ $fp = fopen($filename, "w");
+ $characters = << 0) {
+ if ($size < $part_size) {
+ $write_size = $size;
+ } else {
+ $write_size = $part_size;
+ }
+ $size -= $write_size;
+ $a = $characters[rand(0, $charactersLength - 1)];
+ $content = str_repeat($a, $write_size);
+ $flag = fwrite($fp, $content);
+ if (!$flag) {
+ echo "write to " . $filename . " failed. ";
+ break;
+ }
+ }
+ } else {
+ echo "open " . $filename . " failed. ";
+ }
+ fclose($fp);
+ }
+
+ /**
+ * 得到文件的md5编码
+ *
+ * @param $filename
+ * @param $from_pos
+ * @param $to_pos
+ * @return string
+ */
+ public static function getMd5SumForFile($filename, $from_pos, $to_pos)
+ {
+ $content_md5 = "";
+ if (($to_pos - $from_pos) > self::OSS_MAX_PART_SIZE) {
+ return $content_md5;
+ }
+ $filesize = filesize($filename);
+ if ($from_pos >= $filesize || $to_pos >= $filesize || $from_pos < 0 || $to_pos < 0) {
+ return $content_md5;
+ }
+
+ $total_length = $to_pos - $from_pos + 1;
+ $buffer = 8192;
+ $left_length = $total_length;
+ if (!file_exists($filename)) {
+ return $content_md5;
+ }
+
+ if (false === $fh = fopen($filename, 'rb')) {
+ return $content_md5;
+ }
+
+ fseek($fh, $from_pos);
+ $data = '';
+ while (!feof($fh)) {
+ if ($left_length >= $buffer) {
+ $read_length = $buffer;
+ } else {
+ $read_length = $left_length;
+ }
+ if ($read_length <= 0) {
+ break;
+ } else {
+ $data .= fread($fh, $read_length);
+ $left_length = $left_length - $read_length;
+ }
+ }
+ fclose($fh);
+ $content_md5 = base64_encode(md5($data, true));
+ return $content_md5;
+ }
+
+ /**
+ * 检测是否windows系统,因为windows系统默认编码为GBK
+ *
+ * @return bool
+ */
+ public static function isWin()
+ {
+ return strtoupper(substr(PHP_OS, 0, 3)) == "WIN";
+ }
+
+ /**
+ * 主要是由于windows系统编码是gbk,遇到中文时候,如果不进行转换处理会出现找不到文件的问题
+ *
+ * @param $file_path
+ * @return string
+ */
+ public static function encodePath($file_path)
+ {
+ if (self::chkChinese($file_path) && self::isWin()) {
+ $file_path = iconv('utf-8', 'gbk', $file_path);
+ }
+ return $file_path;
+ }
+
+ /**
+ * 判断用户输入的endpoint是否是 xxx.xxx.xxx.xxx:port 或者 xxx.xxx.xxx.xxx的ip格式
+ *
+ * @param string $endpoint 需要做判断的endpoint
+ * @return boolean
+ */
+ public static function isIPFormat($endpoint)
+ {
+ $ip_array = explode(":", $endpoint);
+ $hostname = $ip_array[0];
+ $ret = filter_var($hostname, FILTER_VALIDATE_IP);
+ if (!$ret) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /**
+ * 生成DeleteMultiObjects接口的xml消息
+ *
+ * @param string[] $objects
+ * @param bool $quiet
+ * @return string
+ */
+ public static function createDeleteObjectsXmlBody($objects, $quiet)
+ {
+ $xml = new \SimpleXMLElement(' ');
+ $xml->addChild('Quiet', $quiet);
+ foreach ($objects as $object) {
+ $sub_object = $xml->addChild('Object');
+ $object = OssUtil::sReplace($object);
+ $sub_object->addChild('Key', $object);
+ }
+ return $xml->asXML();
+ }
+
+ /**
+ * 生成CompleteMultipartUpload接口的xml消息
+ *
+ * @param array[] $listParts
+ * @return string
+ */
+ public static function createCompleteMultipartUploadXmlBody($listParts)
+ {
+ $xml = new \SimpleXMLElement(' ');
+ foreach ($listParts as $node) {
+ $part = $xml->addChild('Part');
+ $part->addChild('PartNumber', $node['PartNumber']);
+ $part->addChild('ETag', $node['ETag']);
+ }
+ return $xml->asXML();
+ }
+
+ /**
+ * 读取目录
+ *
+ * @param string $dir
+ * @param string $exclude
+ * @param bool $recursive
+ * @return string[]
+ */
+ public static function readDir($dir, $exclude = ".|..|.svn|.git", $recursive = false)
+ {
+ $file_list_array = array();
+ $base_path = $dir;
+ $exclude_array = explode("|", $exclude);
+ $exclude_array = array_unique(array_merge($exclude_array, array('.', '..')));
+
+ if ($recursive) {
+ foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir)) as $new_file) {
+ if ($new_file->isDir()) continue;
+ $object = str_replace($base_path, '', $new_file);
+ if (!in_array(strtolower($object), $exclude_array)) {
+ $object = ltrim($object, '/');
+ if (is_file($new_file)) {
+ $key = md5($new_file . $object, false);
+ $file_list_array[$key] = array('path' => $new_file, 'file' => $object,);
+ }
+ }
+ }
+ } else if ($handle = opendir($dir)) {
+ while (false !== ($file = readdir($handle))) {
+ if (!in_array(strtolower($file), $exclude_array)) {
+ $new_file = $dir . '/' . $file;
+ $object = $file;
+ $object = ltrim($object, '/');
+ if (is_file($new_file)) {
+ $key = md5($new_file . $object, false);
+ $file_list_array[$key] = array('path' => $new_file, 'file' => $object,);
+ }
+ }
+ }
+ closedir($handle);
+ }
+ return $file_list_array;
+ }
+
+ /**
+ * Decode key based on the encoding type
+ *
+ * @param string $key
+ * @param string $encoding
+ * @return string
+ */
+ public static function decodeKey($key, $encoding)
+ {
+ if ($encoding == "") {
+ return $key;
+ }
+
+ if ($encoding == "url") {
+ return rawurldecode($key);
+ } else {
+ throw new OssException("Unrecognized encoding type: " . $encoding);
+ }
+ }
+}
diff --git a/addons/alioss/library/OSS/Http/LICENSE b/addons/alioss/library/OSS/Http/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..49b38bd620ac6d804660351a60b6e37e80a691ac
--- /dev/null
+++ b/addons/alioss/library/OSS/Http/LICENSE
@@ -0,0 +1,25 @@
+Copyright (c) 2006-2010 Ryan Parman, Foleeo Inc., and contributors. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are
+permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of
+ conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ of conditions and the following disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ * Neither the name of Ryan Parman, Foleeo Inc. nor the names of its contributors may be used to
+ endorse or promote products derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
+OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS
+AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/addons/alioss/library/OSS/Http/RequestCore.php b/addons/alioss/library/OSS/Http/RequestCore.php
new file mode 100644
index 0000000000000000000000000000000000000000..06d0f87839f3579484ad619d3f7a95a487068107
--- /dev/null
+++ b/addons/alioss/library/OSS/Http/RequestCore.php
@@ -0,0 +1,896 @@
+).
+ */
+ public $request_class = 'OSS\Http\RequestCore';
+
+ /**
+ * The default class to use for HTTP Responses (defaults to ).
+ */
+ public $response_class = 'OSS\Http\ResponseCore';
+
+ /**
+ * Default useragent string to use.
+ */
+ public $useragent = 'RequestCore/1.4.3';
+
+ /**
+ * File to read from while streaming up.
+ */
+ public $read_file = null;
+
+ /**
+ * The resource to read from while streaming up.
+ */
+ public $read_stream = null;
+
+ /**
+ * The size of the stream to read from.
+ */
+ public $read_stream_size = null;
+
+ /**
+ * The length already read from the stream.
+ */
+ public $read_stream_read = 0;
+
+ /**
+ * File to write to while streaming down.
+ */
+ public $write_file = null;
+
+ /**
+ * The resource to write to while streaming down.
+ */
+ public $write_stream = null;
+
+ /**
+ * Stores the intended starting seek position.
+ */
+ public $seek_position = null;
+
+ /**
+ * The location of the cacert.pem file to use.
+ */
+ public $cacert_location = false;
+
+ /**
+ * The state of SSL certificate verification.
+ */
+ public $ssl_verification = true;
+
+ /**
+ * The user-defined callback function to call when a stream is read from.
+ */
+ public $registered_streaming_read_callback = null;
+
+ /**
+ * The user-defined callback function to call when a stream is written to.
+ */
+ public $registered_streaming_write_callback = null;
+
+ /**
+ * 请求超时时间, 默认是5184000秒,6天
+ *
+ * @var int
+ */
+ public $timeout = 5184000;
+
+ /**
+ * 连接超时时间,默认是10秒
+ *
+ * @var int
+ */
+ public $connect_timeout = 10;
+
+ /*%******************************************************************************************%*/
+ // CONSTANTS
+
+ /**
+ * GET HTTP Method
+ */
+ const HTTP_GET = 'GET';
+
+ /**
+ * POST HTTP Method
+ */
+ const HTTP_POST = 'POST';
+
+ /**
+ * PUT HTTP Method
+ */
+ const HTTP_PUT = 'PUT';
+
+ /**
+ * DELETE HTTP Method
+ */
+ const HTTP_DELETE = 'DELETE';
+
+ /**
+ * HEAD HTTP Method
+ */
+ const HTTP_HEAD = 'HEAD';
+
+
+ /*%******************************************************************************************%*/
+ // CONSTRUCTOR/DESTRUCTOR
+
+ /**
+ * Constructs a new instance of this class.
+ *
+ * @param string $url (Optional) The URL to request or service endpoint to query.
+ * @param string $proxy (Optional) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port`
+ * @param array $helpers (Optional) An associative array of classnames to use for request, and response functionality. Gets passed in automatically by the calling class.
+ * @return $this A reference to the current instance.
+ */
+ public function __construct($url = null, $proxy = null, $helpers = null)
+ {
+ // Set some default values.
+ $this->request_url = $url;
+ $this->method = self::HTTP_GET;
+ $this->request_headers = array();
+ $this->request_body = '';
+
+ // Set a new Request class if one was set.
+ if (isset($helpers['request']) && !empty($helpers['request'])) {
+ $this->request_class = $helpers['request'];
+ }
+
+ // Set a new Request class if one was set.
+ if (isset($helpers['response']) && !empty($helpers['response'])) {
+ $this->response_class = $helpers['response'];
+ }
+
+ if ($proxy) {
+ $this->set_proxy($proxy);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Destructs the instance. Closes opened file handles.
+ *
+ * @return $this A reference to the current instance.
+ */
+ public function __destruct()
+ {
+ if (isset($this->read_file) && isset($this->read_stream)) {
+ fclose($this->read_stream);
+ }
+
+ if (isset($this->write_file) && isset($this->write_stream)) {
+ fclose($this->write_stream);
+ }
+
+ return $this;
+ }
+
+
+ /*%******************************************************************************************%*/
+ // REQUEST METHODS
+
+ /**
+ * Sets the credentials to use for authentication.
+ *
+ * @param string $user (Required) The username to authenticate with.
+ * @param string $pass (Required) The password to authenticate with.
+ * @return $this A reference to the current instance.
+ */
+ public function set_credentials($user, $pass)
+ {
+ $this->username = $user;
+ $this->password = $pass;
+ return $this;
+ }
+
+ /**
+ * Adds a custom HTTP header to the cURL request.
+ *
+ * @param string $key (Required) The custom HTTP header to set.
+ * @param mixed $value (Required) The value to assign to the custom HTTP header.
+ * @return $this A reference to the current instance.
+ */
+ public function add_header($key, $value)
+ {
+ $this->request_headers[$key] = $value;
+ return $this;
+ }
+
+ /**
+ * Removes an HTTP header from the cURL request.
+ *
+ * @param string $key (Required) The custom HTTP header to set.
+ * @return $this A reference to the current instance.
+ */
+ public function remove_header($key)
+ {
+ if (isset($this->request_headers[$key])) {
+ unset($this->request_headers[$key]);
+ }
+ return $this;
+ }
+
+ /**
+ * Set the method type for the request.
+ *
+ * @param string $method (Required) One of the following constants: , , , , .
+ * @return $this A reference to the current instance.
+ */
+ public function set_method($method)
+ {
+ $this->method = strtoupper($method);
+ return $this;
+ }
+
+ /**
+ * Sets a custom useragent string for the class.
+ *
+ * @param string $ua (Required) The useragent string to use.
+ * @return $this A reference to the current instance.
+ */
+ public function set_useragent($ua)
+ {
+ $this->useragent = $ua;
+ return $this;
+ }
+
+ /**
+ * Set the body to send in the request.
+ *
+ * @param string $body (Required) The textual content to send along in the body of the request.
+ * @return $this A reference to the current instance.
+ */
+ public function set_body($body)
+ {
+ $this->request_body = $body;
+ return $this;
+ }
+
+ /**
+ * Set the URL to make the request to.
+ *
+ * @param string $url (Required) The URL to make the request to.
+ * @return $this A reference to the current instance.
+ */
+ public function set_request_url($url)
+ {
+ $this->request_url = $url;
+ return $this;
+ }
+
+ /**
+ * Set additional CURLOPT settings. These will merge with the default settings, and override if
+ * there is a duplicate.
+ *
+ * @param array $curlopts (Optional) A set of key-value pairs that set `CURLOPT` options. These will merge with the existing CURLOPTs, and ones passed here will override the defaults. Keys should be the `CURLOPT_*` constants, not strings.
+ * @return $this A reference to the current instance.
+ */
+ public function set_curlopts($curlopts)
+ {
+ $this->curlopts = $curlopts;
+ return $this;
+ }
+
+ /**
+ * Sets the length in bytes to read from the stream while streaming up.
+ *
+ * @param integer $size (Required) The length in bytes to read from the stream.
+ * @return $this A reference to the current instance.
+ */
+ public function set_read_stream_size($size)
+ {
+ $this->read_stream_size = $size;
+
+ return $this;
+ }
+
+ /**
+ * Sets the resource to read from while streaming up. Reads the stream from its current position until
+ * EOF or `$size` bytes have been read. If `$size` is not given it will be determined by and
+ * .
+ *
+ * @param resource $resource (Required) The readable resource to read from.
+ * @param integer $size (Optional) The size of the stream to read.
+ * @return $this A reference to the current instance.
+ */
+ public function set_read_stream($resource, $size = null)
+ {
+ if (!isset($size) || $size < 0) {
+ $stats = fstat($resource);
+
+ if ($stats && $stats['size'] >= 0) {
+ $position = ftell($resource);
+
+ if ($position !== false && $position >= 0) {
+ $size = $stats['size'] - $position;
+ }
+ }
+ }
+
+ $this->read_stream = $resource;
+
+ return $this->set_read_stream_size($size);
+ }
+
+ /**
+ * Sets the file to read from while streaming up.
+ *
+ * @param string $location (Required) The readable location to read from.
+ * @return $this A reference to the current instance.
+ */
+ public function set_read_file($location)
+ {
+ $this->read_file = $location;
+ $read_file_handle = fopen($location, 'r');
+
+ return $this->set_read_stream($read_file_handle);
+ }
+
+ /**
+ * Sets the resource to write to while streaming down.
+ *
+ * @param resource $resource (Required) The writeable resource to write to.
+ * @return $this A reference to the current instance.
+ */
+ public function set_write_stream($resource)
+ {
+ $this->write_stream = $resource;
+
+ return $this;
+ }
+
+ /**
+ * Sets the file to write to while streaming down.
+ *
+ * @param string $location (Required) The writeable location to write to.
+ * @return $this A reference to the current instance.
+ */
+ public function set_write_file($location)
+ {
+ $this->write_file = $location;
+ }
+
+ /**
+ * Set the proxy to use for making requests.
+ *
+ * @param string $proxy (Required) The faux-url to use for proxy settings. Takes the following format: `proxy://user:pass@hostname:port`
+ * @return $this A reference to the current instance.
+ */
+ public function set_proxy($proxy)
+ {
+ $proxy = parse_url($proxy);
+ $proxy['user'] = isset($proxy['user']) ? $proxy['user'] : null;
+ $proxy['pass'] = isset($proxy['pass']) ? $proxy['pass'] : null;
+ $proxy['port'] = isset($proxy['port']) ? $proxy['port'] : null;
+ $this->proxy = $proxy;
+ return $this;
+ }
+
+ /**
+ * Set the intended starting seek position.
+ *
+ * @param integer $position (Required) The byte-position of the stream to begin reading from.
+ * @return $this A reference to the current instance.
+ */
+ public function set_seek_position($position)
+ {
+ $this->seek_position = isset($position) ? (integer)$position : null;
+
+ return $this;
+ }
+
+ /**
+ * A callback function that is invoked by cURL for streaming up.
+ *
+ * @param resource $curl_handle (Required) The cURL handle for the request.
+ * @param resource $header_content (Required) The header callback result.
+ * @return headers from a stream.
+ */
+ public function streaming_header_callback($curl_handle, $header_content)
+ {
+ $code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);
+
+ if (isset($this->write_file) && intval($code) / 100 == 2 && !isset($this->write_file_handle))
+ {
+ $this->write_file_handle = fopen($this->write_file, 'w');
+ $this->set_write_stream($this->write_file_handle);
+ }
+
+ $this->response_raw_headers .= $header_content;
+ return strlen($header_content);
+ }
+
+
+ /**
+ * Register a callback function to execute whenever a data stream is read from using
+ * .
+ *
+ * The user-defined callback function should accept three arguments:
+ *
+ *
+ * $curl_handle
- resource
- Required - The cURL handle resource that represents the in-progress transfer.
+ * $file_handle
- resource
- Required - The file handle resource that represents the file on the local file system.
+ * $length
- integer
- Required - The length in kilobytes of the data chunk that was transferred.
+ *
+ *
+ * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
+ * The name of a global function to execute, passed as a string.
+ * A method to execute, passed as array('ClassName', 'MethodName')
.
+ * An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance.
+ */
+ public function register_streaming_read_callback($callback)
+ {
+ $this->registered_streaming_read_callback = $callback;
+
+ return $this;
+ }
+
+ /**
+ * Register a callback function to execute whenever a data stream is written to using
+ * .
+ *
+ * The user-defined callback function should accept two arguments:
+ *
+ *
+ * $curl_handle
- resource
- Required - The cURL handle resource that represents the in-progress transfer.
+ * $length
- integer
- Required - The length in kilobytes of the data chunk that was transferred.
+ *
+ *
+ * @param string|array|function $callback (Required) The callback function is called by , so you can pass the following values:
+ * The name of a global function to execute, passed as a string.
+ * A method to execute, passed as array('ClassName', 'MethodName')
.
+ * An anonymous function (PHP 5.3+).
+ * @return $this A reference to the current instance.
+ */
+ public function register_streaming_write_callback($callback)
+ {
+ $this->registered_streaming_write_callback = $callback;
+
+ return $this;
+ }
+
+
+ /*%******************************************************************************************%*/
+ // PREPARE, SEND, AND PROCESS REQUEST
+
+ /**
+ * A callback function that is invoked by cURL for streaming up.
+ *
+ * @param resource $curl_handle (Required) The cURL handle for the request.
+ * @param resource $file_handle (Required) The open file handle resource.
+ * @param integer $length (Required) The maximum number of bytes to read.
+ * @return binary Binary data from a stream.
+ */
+ public function streaming_read_callback($curl_handle, $file_handle, $length)
+ {
+ // Once we've sent as much as we're supposed to send...
+ if ($this->read_stream_read >= $this->read_stream_size) {
+ // Send EOF
+ return '';
+ }
+
+ // If we're at the beginning of an upload and need to seek...
+ if ($this->read_stream_read == 0 && isset($this->seek_position) && $this->seek_position !== ftell($this->read_stream)) {
+ if (fseek($this->read_stream, $this->seek_position) !== 0) {
+ throw new RequestCore_Exception('The stream does not support seeking and is either not at the requested position or the position is unknown.');
+ }
+ }
+
+ $read = fread($this->read_stream, min($this->read_stream_size - $this->read_stream_read, $length)); // Remaining upload data or cURL's requested chunk size
+ $this->read_stream_read += strlen($read);
+
+ $out = $read === false ? '' : $read;
+
+ // Execute callback function
+ if ($this->registered_streaming_read_callback) {
+ call_user_func($this->registered_streaming_read_callback, $curl_handle, $file_handle, $out);
+ }
+
+ return $out;
+ }
+
+ /**
+ * A callback function that is invoked by cURL for streaming down.
+ *
+ * @param resource $curl_handle (Required) The cURL handle for the request.
+ * @param binary $data (Required) The data to write.
+ * @return integer The number of bytes written.
+ */
+ public function streaming_write_callback($curl_handle, $data)
+ {
+ $code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);
+
+ if (intval($code) / 100 != 2)
+ {
+ $this->response_error_body .= $data;
+ return strlen($data);
+ }
+
+ $length = strlen($data);
+ $written_total = 0;
+ $written_last = 0;
+
+ while ($written_total < $length) {
+ $written_last = fwrite($this->write_stream, substr($data, $written_total));
+
+ if ($written_last === false) {
+ return $written_total;
+ }
+
+ $written_total += $written_last;
+ }
+
+ // Execute callback function
+ if ($this->registered_streaming_write_callback) {
+ call_user_func($this->registered_streaming_write_callback, $curl_handle, $written_total);
+ }
+
+ return $written_total;
+ }
+
+ /**
+ * Prepares and adds the details of the cURL request. This can be passed along to a
+ * function.
+ *
+ * @return resource The handle for the cURL object.
+ *
+ */
+ public function prep_request()
+ {
+ $curl_handle = curl_init();
+
+ // Set default options.
+ curl_setopt($curl_handle, CURLOPT_URL, $this->request_url);
+ curl_setopt($curl_handle, CURLOPT_FILETIME, true);
+ curl_setopt($curl_handle, CURLOPT_FRESH_CONNECT, false);
+// curl_setopt($curl_handle, CURLOPT_CLOSEPOLICY, CURLCLOSEPOLICY_LEAST_RECENTLY_USED);
+ curl_setopt($curl_handle, CURLOPT_MAXREDIRS, 5);
+ curl_setopt($curl_handle, CURLOPT_HEADER, true);
+ curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($curl_handle, CURLOPT_TIMEOUT, $this->timeout);
+ curl_setopt($curl_handle, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout);
+ curl_setopt($curl_handle, CURLOPT_NOSIGNAL, true);
+ curl_setopt($curl_handle, CURLOPT_REFERER, $this->request_url);
+ curl_setopt($curl_handle, CURLOPT_USERAGENT, $this->useragent);
+ curl_setopt($curl_handle, CURLOPT_HEADERFUNCTION, array($this, 'streaming_header_callback'));
+ curl_setopt($curl_handle, CURLOPT_READFUNCTION, array($this, 'streaming_read_callback'));
+
+ // Verification of the SSL cert
+ if ($this->ssl_verification) {
+ curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, 2);
+ } else {
+ curl_setopt($curl_handle, CURLOPT_SSL_VERIFYPEER, false);
+ curl_setopt($curl_handle, CURLOPT_SSL_VERIFYHOST, false);
+ }
+
+ // chmod the file as 0755
+ if ($this->cacert_location === true) {
+ curl_setopt($curl_handle, CURLOPT_CAINFO, dirname(__FILE__) . '/cacert.pem');
+ } elseif (is_string($this->cacert_location)) {
+ curl_setopt($curl_handle, CURLOPT_CAINFO, $this->cacert_location);
+ }
+
+ // Debug mode
+ if ($this->debug_mode) {
+ curl_setopt($curl_handle, CURLOPT_VERBOSE, true);
+ }
+
+ // Handle open_basedir & safe mode
+ if (!ini_get('safe_mode') && !ini_get('open_basedir')) {
+ curl_setopt($curl_handle, CURLOPT_FOLLOWLOCATION, true);
+ }
+
+ // Enable a proxy connection if requested.
+ if ($this->proxy) {
+
+ $host = $this->proxy['host'];
+ $host .= ($this->proxy['port']) ? ':' . $this->proxy['port'] : '';
+ curl_setopt($curl_handle, CURLOPT_PROXY, $host);
+
+ if (isset($this->proxy['user']) && isset($this->proxy['pass'])) {
+ curl_setopt($curl_handle, CURLOPT_PROXYUSERPWD, $this->proxy['user'] . ':' . $this->proxy['pass']);
+ }
+ }
+
+ // Set credentials for HTTP Basic/Digest Authentication.
+ if ($this->username && $this->password) {
+ curl_setopt($curl_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+ curl_setopt($curl_handle, CURLOPT_USERPWD, $this->username . ':' . $this->password);
+ }
+
+ // Handle the encoding if we can.
+ if (extension_loaded('zlib')) {
+ curl_setopt($curl_handle, CURLOPT_ENCODING, '');
+ }
+
+ // Process custom headers
+ if (isset($this->request_headers) && count($this->request_headers)) {
+ $temp_headers = array();
+
+ foreach ($this->request_headers as $k => $v) {
+ $temp_headers[] = $k . ': ' . $v;
+ }
+
+ curl_setopt($curl_handle, CURLOPT_HTTPHEADER, $temp_headers);
+ }
+
+ switch ($this->method) {
+ case self::HTTP_PUT:
+ //unset($this->read_stream);
+ curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'PUT');
+ if (isset($this->read_stream)) {
+ if (!isset($this->read_stream_size) || $this->read_stream_size < 0) {
+ throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.');
+ }
+ curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size);
+ curl_setopt($curl_handle, CURLOPT_UPLOAD, true);
+ } else {
+ curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body);
+ }
+ break;
+
+ case self::HTTP_POST:
+ curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, 'POST');
+ if (isset($this->read_stream)) {
+ if (!isset($this->read_stream_size) || $this->read_stream_size < 0) {
+ throw new RequestCore_Exception('The stream size for the streaming upload cannot be determined.');
+ }
+ curl_setopt($curl_handle, CURLOPT_INFILESIZE, $this->read_stream_size);
+ curl_setopt($curl_handle, CURLOPT_UPLOAD, true);
+ } else {
+ curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body);
+ }
+ break;
+
+ case self::HTTP_HEAD:
+ curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, self::HTTP_HEAD);
+ curl_setopt($curl_handle, CURLOPT_NOBODY, 1);
+ break;
+
+ default: // Assumed GET
+ curl_setopt($curl_handle, CURLOPT_CUSTOMREQUEST, $this->method);
+ if (isset($this->write_stream) || isset($this->write_file)) {
+ curl_setopt($curl_handle, CURLOPT_WRITEFUNCTION, array($this, 'streaming_write_callback'));
+ curl_setopt($curl_handle, CURLOPT_HEADER, false);
+ } else {
+ curl_setopt($curl_handle, CURLOPT_POSTFIELDS, $this->request_body);
+ }
+ break;
+ }
+
+ // Merge in the CURLOPTs
+ if (isset($this->curlopts) && sizeof($this->curlopts) > 0) {
+ foreach ($this->curlopts as $k => $v) {
+ curl_setopt($curl_handle, $k, $v);
+ }
+ }
+
+ return $curl_handle;
+ }
+
+ /**
+ * Take the post-processed cURL data and break it down into useful header/body/info chunks. Uses the
+ * data stored in the `curl_handle` and `response` properties unless replacement data is passed in via
+ * parameters.
+ *
+ * @param resource $curl_handle (Optional) The reference to the already executed cURL request.
+ * @param string $response (Optional) The actual response content itself that needs to be parsed.
+ * @return ResponseCore A object containing a parsed HTTP response.
+ */
+ public function process_response($curl_handle = null, $response = null)
+ {
+ // Accept a custom one if it's passed.
+ if ($curl_handle && $response) {
+ $this->response = $response;
+ }
+
+ // As long as this came back as a valid resource...
+ if (is_resource($curl_handle)) {
+ // Determine what's what.
+ $header_size = curl_getinfo($curl_handle, CURLINFO_HEADER_SIZE);
+ $this->response_headers = substr($this->response, 0, $header_size);
+ $this->response_body = substr($this->response, $header_size);
+ $this->response_code = curl_getinfo($curl_handle, CURLINFO_HTTP_CODE);
+ $this->response_info = curl_getinfo($curl_handle);
+
+ if (intval($this->response_code) / 100 != 2 && isset($this->write_file))
+ {
+ $this->response_headers = $this->response_raw_headers;
+ $this->response_body = $this->response_error_body;
+ }
+
+ // Parse out the headers
+ $this->response_headers = explode("\r\n\r\n", trim($this->response_headers));
+ $this->response_headers = array_pop($this->response_headers);
+ $this->response_headers = explode("\r\n", $this->response_headers);
+ array_shift($this->response_headers);
+
+ // Loop through and split up the headers.
+ $header_assoc = array();
+ foreach ($this->response_headers as $header) {
+ $kv = explode(': ', $header);
+ $header_assoc[strtolower($kv[0])] = isset($kv[1]) ? $kv[1] : '';
+ }
+
+ // Reset the headers to the appropriate property.
+ $this->response_headers = $header_assoc;
+ $this->response_headers['info'] = $this->response_info;
+ $this->response_headers['info']['method'] = $this->method;
+
+ if ($curl_handle && $response) {
+ return new ResponseCore($this->response_headers, $this->response_body, $this->response_code);
+ }
+ }
+
+ // Return false
+ return false;
+ }
+
+ /**
+ * Sends the request, calling necessary utility functions to update built-in properties.
+ *
+ * @param boolean $parse (Optional) Whether to parse the response with ResponseCore or not.
+ * @return string The resulting unparsed data from the request.
+ */
+ public function send_request($parse = false)
+ {
+ set_time_limit(0);
+
+ $curl_handle = $this->prep_request();
+ $this->response = curl_exec($curl_handle);
+
+ if ($this->response === false) {
+ throw new RequestCore_Exception('cURL resource: ' . (string)$curl_handle . '; cURL error: ' . curl_error($curl_handle) . ' (' . curl_errno($curl_handle) . ')');
+ }
+
+ $parsed_response = $this->process_response($curl_handle, $this->response);
+
+ curl_close($curl_handle);
+
+ if ($parse) {
+ return $parsed_response;
+ }
+
+ return $this->response;
+ }
+
+ /*%******************************************************************************************%*/
+ // RESPONSE METHODS
+
+ /**
+ * Get the HTTP response headers from the request.
+ *
+ * @param string $header (Optional) A specific header value to return. Defaults to all headers.
+ * @return string|array All or selected header values.
+ */
+ public function get_response_header($header = null)
+ {
+ if ($header) {
+ return $this->response_headers[strtolower($header)];
+ }
+ return $this->response_headers;
+ }
+
+ /**
+ * Get the HTTP response body from the request.
+ *
+ * @return string The response body.
+ */
+ public function get_response_body()
+ {
+ return $this->response_body;
+ }
+
+ /**
+ * Get the HTTP response code from the request.
+ *
+ * @return string The HTTP response code.
+ */
+ public function get_response_code()
+ {
+ return $this->response_code;
+ }
+}
diff --git a/addons/alioss/library/OSS/Http/RequestCore_Exception.php b/addons/alioss/library/OSS/Http/RequestCore_Exception.php
new file mode 100644
index 0000000000000000000000000000000000000000..cb4e83c652f728f30418ba3b48dc9b2566364b74
--- /dev/null
+++ b/addons/alioss/library/OSS/Http/RequestCore_Exception.php
@@ -0,0 +1,8 @@
+).
+ * @param string $body (Required) XML-formatted response from AWS.
+ * @param integer $status (Optional) HTTP response status code from the request.
+ * @return Mixed Contains an `header` property (HTTP headers as an associative array), a or `body` property, and an `status` code.
+ */
+ public function __construct($header, $body, $status = null)
+ {
+ $this->header = $header;
+ $this->body = $body;
+ $this->status = $status;
+
+ return $this;
+ }
+
+ /**
+ * Did we receive the status code we expected?
+ *
+ * @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.
+ * @return boolean Whether we received the expected status code or not.
+ */
+ public function isOK($codes = array(200, 201, 204, 206))
+ {
+ if (is_array($codes)) {
+ return in_array($this->status, $codes);
+ }
+
+ return $this->status === $codes;
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/BucketInfo.php b/addons/alioss/library/OSS/Model/BucketInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..9b89674f974640b8a1dab4fb600a66c436022fdd
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/BucketInfo.php
@@ -0,0 +1,78 @@
+location = $location;
+ $this->name = $name;
+ $this->createDate = $createDate;
+ }
+
+ /**
+ * 得到bucket所在的region
+ *
+ * @return string
+ */
+ public function getLocation()
+ {
+ return $this->location;
+ }
+
+ /**
+ * 得到bucket的名称
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * 得到bucket的创建时间
+ *
+ * @return string
+ */
+ public function getCreateDate()
+ {
+ return $this->createDate;
+ }
+
+ /**
+ * bucket所在的region
+ *
+ * @var string
+ */
+ private $location;
+ /**
+ * bucket的名称
+ *
+ * @var string
+ */
+ private $name;
+
+ /**
+ * bucket的创建事件
+ *
+ * @var string
+ */
+ private $createDate;
+
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/BucketListInfo.php b/addons/alioss/library/OSS/Model/BucketListInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..910717f924d3d7a713cb725ae2990cbf7f5b269a
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/BucketListInfo.php
@@ -0,0 +1,39 @@
+bucketList = $bucketList;
+ }
+
+ /**
+ * 得到BucketInfo列表
+ *
+ * @return BucketInfo[]
+ */
+ public function getBucketList()
+ {
+ return $this->bucketList;
+ }
+
+ /**
+ * BucketInfo信息列表
+ *
+ * @var array
+ */
+ private $bucketList = array();
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/CnameConfig.php b/addons/alioss/library/OSS/Model/CnameConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..f3597d2f06bbc754bb23f1f43131bc78f75f7852
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/CnameConfig.php
@@ -0,0 +1,99 @@
+cnameList = array();
+ }
+
+ /**
+ * @return array
+ * @example
+ * array(2) {
+ * [0]=>
+ * array(3) {
+ * ["Domain"]=>
+ * string(11) "www.foo.com"
+ * ["Status"]=>
+ * string(7) "enabled"
+ * ["LastModified"]=>
+ * string(8) "20150101"
+ * }
+ * [1]=>
+ * array(3) {
+ * ["Domain"]=>
+ * string(7) "bar.com"
+ * ["Status"]=>
+ * string(8) "disabled"
+ * ["LastModified"]=>
+ * string(8) "20160101"
+ * }
+ * }
+ */
+ public function getCnames()
+ {
+ return $this->cnameList;
+ }
+
+
+ public function addCname($cname)
+ {
+ if (count($this->cnameList) >= self::OSS_MAX_RULES) {
+ throw new OssException(
+ "num of cname in the config exceeds self::OSS_MAX_RULES: " . strval(self::OSS_MAX_RULES));
+ }
+ $this->cnameList[] = array('Domain' => $cname);
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ if (!isset($xml->Cname)) return;
+ foreach ($xml->Cname as $entry) {
+ $cname = array();
+ foreach ($entry as $key => $value) {
+ $cname[strval($key)] = strval($value);
+ }
+ $this->cnameList[] = $cname;
+ }
+ }
+
+ public function serializeToXml()
+ {
+ $strXml = <<
+
+
+EOF;
+ $xml = new \SimpleXMLElement($strXml);
+ foreach ($this->cnameList as $cname) {
+ $node = $xml->addChild('Cname');
+ foreach ($cname as $key => $value) {
+ $node->addChild($key, $value);
+ }
+ }
+ return $xml->asXML();
+ }
+
+ public function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ const OSS_MAX_RULES = 10;
+
+ private $cnameList = array();
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/CorsConfig.php b/addons/alioss/library/OSS/Model/CorsConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..c44c10a1a2d176058b032457b51f535000628151
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/CorsConfig.php
@@ -0,0 +1,113 @@
+rules = array();
+ }
+
+ /**
+ * 得到CorsRule列表
+ *
+ * @return CorsRule[]
+ */
+ public function getRules()
+ {
+ return $this->rules;
+ }
+
+
+ /**
+ * 添加一条CorsRule
+ *
+ * @param CorsRule $rule
+ * @throws OssException
+ */
+ public function addRule($rule)
+ {
+ if (count($this->rules) >= self::OSS_MAX_RULES) {
+ throw new OssException("num of rules in the config exceeds self::OSS_MAX_RULES: " . strval(self::OSS_MAX_RULES));
+ }
+ $this->rules[] = $rule;
+ }
+
+ /**
+ * 从xml数据中解析出CorsConfig
+ *
+ * @param string $strXml
+ * @throws OssException
+ * @return null
+ */
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ if (!isset($xml->CORSRule)) return;
+ foreach ($xml->CORSRule as $rule) {
+ $corsRule = new CorsRule();
+ foreach ($rule as $key => $value) {
+ if ($key === self::OSS_CORS_ALLOWED_HEADER) {
+ $corsRule->addAllowedHeader(strval($value));
+ } elseif ($key === self::OSS_CORS_ALLOWED_METHOD) {
+ $corsRule->addAllowedMethod(strval($value));
+ } elseif ($key === self::OSS_CORS_ALLOWED_ORIGIN) {
+ $corsRule->addAllowedOrigin(strval($value));
+ } elseif ($key === self::OSS_CORS_EXPOSE_HEADER) {
+ $corsRule->addExposeHeader(strval($value));
+ } elseif ($key === self::OSS_CORS_MAX_AGE_SECONDS) {
+ $corsRule->setMaxAgeSeconds(strval($value));
+ }
+ }
+ $this->addRule($corsRule);
+ }
+ return;
+ }
+
+ /**
+ * 生成xml字符串
+ *
+ * @return string
+ */
+ public function serializeToXml()
+ {
+ $xml = new \SimpleXMLElement(' ');
+ foreach ($this->rules as $rule) {
+ $xmlRule = $xml->addChild('CORSRule');
+ $rule->appendToXml($xmlRule);
+ }
+ return $xml->asXML();
+ }
+
+ public function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ const OSS_CORS_ALLOWED_ORIGIN = 'AllowedOrigin';
+ const OSS_CORS_ALLOWED_METHOD = 'AllowedMethod';
+ const OSS_CORS_ALLOWED_HEADER = 'AllowedHeader';
+ const OSS_CORS_EXPOSE_HEADER = 'ExposeHeader';
+ const OSS_CORS_MAX_AGE_SECONDS = 'MaxAgeSeconds';
+ const OSS_MAX_RULES = 10;
+
+ /**
+ * orsRule列表
+ *
+ * @var CorsRule[]
+ */
+ private $rules = array();
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/CorsRule.php b/addons/alioss/library/OSS/Model/CorsRule.php
new file mode 100644
index 0000000000000000000000000000000000000000..2cbe1c17b43552d8d14b51442e53538d89de2966
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/CorsRule.php
@@ -0,0 +1,150 @@
+allowedOrigins[] = $allowedOrigin;
+ }
+ }
+
+ /**
+ * Rule中增加一条allowedMethod
+ *
+ * @param string $allowedMethod
+ */
+ public function addAllowedMethod($allowedMethod)
+ {
+ if (!empty($allowedMethod)) {
+ $this->allowedMethods[] = $allowedMethod;
+ }
+ }
+
+ /**
+ * Rule中增加一条allowedHeader
+ *
+ * @param string $allowedHeader
+ */
+ public function addAllowedHeader($allowedHeader)
+ {
+ if (!empty($allowedHeader)) {
+ $this->allowedHeaders[] = $allowedHeader;
+ }
+ }
+
+ /**
+ * Rule中增加一条exposeHeader
+ *
+ * @param string $exposeHeader
+ */
+ public function addExposeHeader($exposeHeader)
+ {
+ if (!empty($exposeHeader)) {
+ $this->exposeHeaders[] = $exposeHeader;
+ }
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxAgeSeconds()
+ {
+ return $this->maxAgeSeconds;
+ }
+
+ /**
+ * @param int $maxAgeSeconds
+ */
+ public function setMaxAgeSeconds($maxAgeSeconds)
+ {
+ $this->maxAgeSeconds = $maxAgeSeconds;
+ }
+
+ /**
+ * 得到AllowedHeaders列表
+ *
+ * @return string[]
+ */
+ public function getAllowedHeaders()
+ {
+ return $this->allowedHeaders;
+ }
+
+ /**
+ * 得到AllowedOrigins列表
+ *
+ * @return string[]
+ */
+ public function getAllowedOrigins()
+ {
+ return $this->allowedOrigins;
+ }
+
+ /**
+ * 得到AllowedMethods列表
+ *
+ * @return string[]
+ */
+ public function getAllowedMethods()
+ {
+ return $this->allowedMethods;
+ }
+
+ /**
+ * 得到ExposeHeaders列表
+ *
+ * @return string[]
+ */
+ public function getExposeHeaders()
+ {
+ return $this->exposeHeaders;
+ }
+
+ /**
+ * 根据提供的xmlRule, 把this按照一定的规则插入到$xmlRule中
+ *
+ * @param \SimpleXMLElement $xmlRule
+ * @throws OssException
+ */
+ public function appendToXml(&$xmlRule)
+ {
+ if (!isset($this->maxAgeSeconds)) {
+ throw new OssException("maxAgeSeconds is not set in the Rule");
+ }
+ foreach ($this->allowedOrigins as $allowedOrigin) {
+ $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_ORIGIN, $allowedOrigin);
+ }
+ foreach ($this->allowedMethods as $allowedMethod) {
+ $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_METHOD, $allowedMethod);
+ }
+ foreach ($this->allowedHeaders as $allowedHeader) {
+ $xmlRule->addChild(CorsConfig::OSS_CORS_ALLOWED_HEADER, $allowedHeader);
+ }
+ foreach ($this->exposeHeaders as $exposeHeader) {
+ $xmlRule->addChild(CorsConfig::OSS_CORS_EXPOSE_HEADER, $exposeHeader);
+ }
+ $xmlRule->addChild(CorsConfig::OSS_CORS_MAX_AGE_SECONDS, strval($this->maxAgeSeconds));
+ }
+
+ private $allowedHeaders = array();
+ private $allowedOrigins = array();
+ private $allowedMethods = array();
+ private $exposeHeaders = array();
+ private $maxAgeSeconds = null;
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/GetLiveChannelHistory.php b/addons/alioss/library/OSS/Model/GetLiveChannelHistory.php
new file mode 100644
index 0000000000000000000000000000000000000000..6643444aac51180d67a12510da3a25a01337b599
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/GetLiveChannelHistory.php
@@ -0,0 +1,34 @@
+liveRecordList;
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+
+ if (isset($xml->LiveRecord)) {
+ foreach ($xml->LiveRecord as $record) {
+ $liveRecord = new LiveChannelHistory();
+ $liveRecord->parseFromXmlNode($record);
+ $this->liveRecordList[] = $liveRecord;
+ }
+ }
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $liveRecordList = array();
+}
diff --git a/addons/alioss/library/OSS/Model/GetLiveChannelInfo.php b/addons/alioss/library/OSS/Model/GetLiveChannelInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..0b5edfc4d1ede684ab48e3302de29f36d54a14a3
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/GetLiveChannelInfo.php
@@ -0,0 +1,68 @@
+description;
+ }
+
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ public function getFragDuration()
+ {
+ return $this->fragDuration;
+ }
+
+ public function getFragCount()
+ {
+ return $this->fragCount;
+ }
+
+ public function getPlayListName()
+ {
+ return $this->playlistName;
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+
+ $this->description = strval($xml->Description);
+ $this->status = strval($xml->Status);
+
+ if (isset($xml->Target)) {
+ foreach ($xml->Target as $target) {
+ $this->type = strval($target->Type);
+ $this->fragDuration = strval($target->FragDuration);
+ $this->fragCount = strval($target->FragCount);
+ $this->playlistName = strval($target->PlaylistName);
+ }
+ }
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $description;
+ private $status;
+ private $type;
+ private $fragDuration;
+ private $fragCount;
+ private $playlistName;
+}
diff --git a/addons/alioss/library/OSS/Model/GetLiveChannelStatus.php b/addons/alioss/library/OSS/Model/GetLiveChannelStatus.php
new file mode 100644
index 0000000000000000000000000000000000000000..2ee7a68b242d550238cd558ae4c44552c99c5093
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/GetLiveChannelStatus.php
@@ -0,0 +1,107 @@
+status;
+ }
+
+ public function getConnectedTime()
+ {
+ return $this->connectedTime;
+ }
+
+ public function getRemoteAddr()
+ {
+ return $this->remoteAddr;
+ }
+
+ public function getVideoWidth()
+ {
+ return $this->videoWidth;
+ }
+ public function getVideoHeight()
+ {
+ return $this->videoHeight;
+ }
+ public function getVideoFrameRate()
+ {
+ return $this->videoFrameRate;
+ }
+ public function getVideoBandwidth()
+ {
+ return $this->videoBandwidth;
+ }
+ public function getVideoCodec()
+ {
+ return $this->videoCodec;
+ }
+
+ public function getAudioBandwidth()
+ {
+ return $this->audioBandwidth;
+ }
+ public function getAudioSampleRate()
+ {
+ return $this->audioSampleRate;
+ }
+ public function getAudioCodec()
+ {
+ return $this->audioCodec;
+ }
+
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ $this->status = strval($xml->Status);
+ $this->connectedTime = strval($xml->ConnectedTime);
+ $this->remoteAddr = strval($xml->RemoteAddr);
+
+ if (isset($xml->Video)) {
+ foreach ($xml->Video as $video) {
+ $this->videoWidth = intval($video->Width);
+ $this->videoHeight = intval($video->Height);
+ $this->videoFrameRate = intval($video->FrameRate);
+ $this->videoBandwidth = intval($video->Bandwidth);
+ $this->videoCodec = strval($video->Codec);
+ }
+ }
+
+ if (isset($xml->Video)) {
+ foreach ($xml->Audio as $audio) {
+ $this->audioBandwidth = intval($audio->Bandwidth);
+ $this->audioSampleRate = intval($audio->SampleRate);
+ $this->audioCodec = strval($audio->Codec);
+ }
+ }
+
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $status;
+ private $connectedTime;
+ private $remoteAddr;
+
+ private $videoWidth;
+ private $videoHeight;
+ private $videoFrameRate;
+ private $videoBandwidth;
+ private $videoCodec;
+
+ private $audioBandwidth;
+ private $audioSampleRate;
+ private $audioCodec;
+
+
+}
diff --git a/addons/alioss/library/OSS/Model/LifecycleAction.php b/addons/alioss/library/OSS/Model/LifecycleAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..5abd825d0cc57639264b0c47f942fd644620c174
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/LifecycleAction.php
@@ -0,0 +1,88 @@
+action = $action;
+ $this->timeSpec = $timeSpec;
+ $this->timeValue = $timeValue;
+ }
+
+ /**
+ * @return LifecycleAction
+ */
+ public function getAction()
+ {
+ return $this->action;
+ }
+
+ /**
+ * @param string $action
+ */
+ public function setAction($action)
+ {
+ $this->action = $action;
+ }
+
+ /**
+ * @return string
+ */
+ public function getTimeSpec()
+ {
+ return $this->timeSpec;
+ }
+
+ /**
+ * @param string $timeSpec
+ */
+ public function setTimeSpec($timeSpec)
+ {
+ $this->timeSpec = $timeSpec;
+ }
+
+ /**
+ * @return string
+ */
+ public function getTimeValue()
+ {
+ return $this->timeValue;
+ }
+
+ /**
+ * @param string $timeValue
+ */
+ public function setTimeValue($timeValue)
+ {
+ $this->timeValue = $timeValue;
+ }
+
+ /**
+ * appendToXml 把actions插入到xml中
+ *
+ * @param \SimpleXMLElement $xmlRule
+ */
+ public function appendToXml(&$xmlRule)
+ {
+ $xmlAction = $xmlRule->addChild($this->action);
+ $xmlAction->addChild($this->timeSpec, $this->timeValue);
+ }
+
+ private $action;
+ private $timeSpec;
+ private $timeValue;
+
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/LifecycleConfig.php b/addons/alioss/library/OSS/Model/LifecycleConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..fc4f5755a63cc057ec704c8b84fae886c5f5ab41
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/LifecycleConfig.php
@@ -0,0 +1,107 @@
+rules = array();
+ $xml = simplexml_load_string($strXml);
+ if (!isset($xml->Rule)) return;
+ $this->rules = array();
+ foreach ($xml->Rule as $rule) {
+ $id = strval($rule->ID);
+ $prefix = strval($rule->Prefix);
+ $status = strval($rule->Status);
+ $actions = array();
+ foreach ($rule as $key => $value) {
+ if ($key === 'ID' || $key === 'Prefix' || $key === 'Status') continue;
+ $action = $key;
+ $timeSpec = null;
+ $timeValue = null;
+ foreach ($value as $timeSpecKey => $timeValueValue) {
+ $timeSpec = $timeSpecKey;
+ $timeValue = strval($timeValueValue);
+ }
+ $actions[] = new LifecycleAction($action, $timeSpec, $timeValue);
+ }
+ $this->rules[] = new LifecycleRule($id, $prefix, $status, $actions);
+ }
+ return;
+ }
+
+
+ /**
+ * 生成xml字符串
+ *
+ * @return string
+ */
+ public function serializeToXml()
+ {
+
+ $xml = new \SimpleXMLElement(' ');
+ foreach ($this->rules as $rule) {
+ $xmlRule = $xml->addChild('Rule');
+ $rule->appendToXml($xmlRule);
+ }
+ return $xml->asXML();
+ }
+
+ /**
+ *
+ * 添加LifecycleRule
+ *
+ * @param LifecycleRule $lifecycleRule
+ * @throws OssException
+ */
+ public function addRule($lifecycleRule)
+ {
+ if (!isset($lifecycleRule)) {
+ throw new OssException("lifecycleRule is null");
+ }
+ $this->rules[] = $lifecycleRule;
+ }
+
+ /**
+ * 将配置转换成字符串,便于用户查看
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ /**
+ * 得到所有的生命周期规则
+ *
+ * @return LifecycleRule[]
+ */
+ public function getRules()
+ {
+ return $this->rules;
+ }
+
+ /**
+ * @var LifecycleRule[]
+ */
+ private $rules;
+}
+
+
diff --git a/addons/alioss/library/OSS/Model/LifecycleRule.php b/addons/alioss/library/OSS/Model/LifecycleRule.php
new file mode 100644
index 0000000000000000000000000000000000000000..ec615b9af18394b519db6f31d4444d3c6f30c576
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/LifecycleRule.php
@@ -0,0 +1,126 @@
+id;
+ }
+
+ /**
+ * @param string $id 规则ID
+ */
+ public function setId($id)
+ {
+ $this->id = $id;
+ }
+
+ /**
+ * 得到文件前缀
+ *
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * 设置文件前缀
+ *
+ * @param string $prefix 文件前缀
+ */
+ public function setPrefix($prefix)
+ {
+ $this->prefix = $prefix;
+ }
+
+ /**
+ * Lifecycle规则的状态
+ *
+ * @return string
+ */
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ /**
+ * 设置Lifecycle规则状态
+ *
+ * @param string $status
+ */
+ public function setStatus($status)
+ {
+ $this->status = $status;
+ }
+
+ /**
+ *
+ * @return LifecycleAction[]
+ */
+ public function getActions()
+ {
+ return $this->actions;
+ }
+
+ /**
+ * @param LifecycleAction[] $actions
+ */
+ public function setActions($actions)
+ {
+ $this->actions = $actions;
+ }
+
+
+ /**
+ * LifecycleRule constructor.
+ *
+ * @param string $id 规则ID
+ * @param string $prefix 文件前缀
+ * @param string $status 规则状态,可选[self::LIFECYCLE_STATUS_ENABLED, self::LIFECYCLE_STATUS_DISABLED]
+ * @param LifecycleAction[] $actions
+ */
+ public function __construct($id, $prefix, $status, $actions)
+ {
+ $this->id = $id;
+ $this->prefix = $prefix;
+ $this->status = $status;
+ $this->actions = $actions;
+ }
+
+ /**
+ * @param \SimpleXMLElement $xmlRule
+ */
+ public function appendToXml(&$xmlRule)
+ {
+ $xmlRule->addChild('ID', $this->id);
+ $xmlRule->addChild('Prefix', $this->prefix);
+ $xmlRule->addChild('Status', $this->status);
+ foreach ($this->actions as $action) {
+ $action->appendToXml($xmlRule);
+ }
+ }
+
+ private $id;
+ private $prefix;
+ private $status;
+ private $actions = array();
+
+ const LIFECYCLE_STATUS_ENABLED = 'Enabled';
+ const LIFECYCLE_STATUS_DISABLED = 'Disabled';
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/ListMultipartUploadInfo.php b/addons/alioss/library/OSS/Model/ListMultipartUploadInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..105d005b2fd319095471ae54f101f291fcc1d25a
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/ListMultipartUploadInfo.php
@@ -0,0 +1,134 @@
+bucket = $bucket;
+ $this->keyMarker = $keyMarker;
+ $this->uploadIdMarker = $uploadIdMarker;
+ $this->nextKeyMarker = $nextKeyMarker;
+ $this->nextUploadIdMarker = $nextUploadIdMarker;
+ $this->delimiter = $delimiter;
+ $this->prefix = $prefix;
+ $this->maxUploads = $maxUploads;
+ $this->isTruncated = $isTruncated;
+ $this->uploads = $uploads;
+ }
+
+ /**
+ * 得到bucket名称
+ *
+ * @return string
+ */
+ public function getBucket()
+ {
+ return $this->bucket;
+ }
+
+ /**
+ * @return string
+ */
+ public function getKeyMarker()
+ {
+ return $this->keyMarker;
+ }
+
+ /**
+ *
+ * @return string
+ */
+ public function getUploadIdMarker()
+ {
+ return $this->uploadIdMarker;
+ }
+
+ /**
+ * @return string
+ */
+ public function getNextKeyMarker()
+ {
+ return $this->nextKeyMarker;
+ }
+
+ /**
+ * @return string
+ */
+ public function getNextUploadIdMarker()
+ {
+ return $this->nextUploadIdMarker;
+ }
+
+ /**
+ * @return string
+ */
+ public function getDelimiter()
+ {
+ return $this->delimiter;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxUploads()
+ {
+ return $this->maxUploads;
+ }
+
+ /**
+ * @return string
+ */
+ public function getIsTruncated()
+ {
+ return $this->isTruncated;
+ }
+
+ /**
+ * @return UploadInfo[]
+ */
+ public function getUploads()
+ {
+ return $this->uploads;
+ }
+
+ private $bucket = "";
+ private $keyMarker = "";
+ private $uploadIdMarker = "";
+ private $nextKeyMarker = "";
+ private $nextUploadIdMarker = "";
+ private $delimiter = "";
+ private $prefix = "";
+ private $maxUploads = 0;
+ private $isTruncated = "false";
+ private $uploads = array();
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/ListPartsInfo.php b/addons/alioss/library/OSS/Model/ListPartsInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..f1d10ee9ee6788c7340f138b9edc9202f48dc856
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/ListPartsInfo.php
@@ -0,0 +1,97 @@
+bucket = $bucket;
+ $this->key = $key;
+ $this->uploadId = $uploadId;
+ $this->nextPartNumberMarker = $nextPartNumberMarker;
+ $this->maxParts = $maxParts;
+ $this->isTruncated = $isTruncated;
+ $this->listPart = $listPart;
+ }
+
+ /**
+ * @return string
+ */
+ public function getBucket()
+ {
+ return $this->bucket;
+ }
+
+ /**
+ * @return string
+ */
+ public function getKey()
+ {
+ return $this->key;
+ }
+
+ /**
+ * @return string
+ */
+ public function getUploadId()
+ {
+ return $this->uploadId;
+ }
+
+ /**
+ * @return int
+ */
+ public function getNextPartNumberMarker()
+ {
+ return $this->nextPartNumberMarker;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxParts()
+ {
+ return $this->maxParts;
+ }
+
+ /**
+ * @return string
+ */
+ public function getIsTruncated()
+ {
+ return $this->isTruncated;
+ }
+
+ /**
+ * @return array
+ */
+ public function getListPart()
+ {
+ return $this->listPart;
+ }
+
+ private $bucket = "";
+ private $key = "";
+ private $uploadId = "";
+ private $nextPartNumberMarker = 0;
+ private $maxParts = 0;
+ private $isTruncated = "";
+ private $listPart = array();
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/LiveChannelConfig.php b/addons/alioss/library/OSS/Model/LiveChannelConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..dadedc911b5b77aa5fde42536aecdcdbbd4ecdb1
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/LiveChannelConfig.php
@@ -0,0 +1,121 @@
+description = $option['description'];
+ }
+ if (isset($option['status'])) {
+ $this->status = $option['status'];
+ }
+ if (isset($option['type'])) {
+ $this->type = $option['type'];
+ }
+ if (isset($option['fragDuration'])) {
+ $this->fragDuration = $option['fragDuration'];
+ }
+ if (isset($option['fragCount'])) {
+ $this->fragCount = $option['fragCount'];
+ }
+ if (isset($option['playListName'])) {
+ $this->playListName = $option['playListName'];
+ }
+ }
+
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ public function getFragDuration()
+ {
+ return $this->fragDuration;
+ }
+
+ public function getFragCount()
+ {
+ return $this->fragCount;
+ }
+
+ public function getPlayListName()
+ {
+ return $this->playListName;
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ $this->description = strval($xml->Description);
+ $this->status = strval($xml->Status);
+ $target = $xml->Target;
+ $this->type = strval($target->Type);
+ $this->fragDuration = intval($target->FragDuration);
+ $this->fragCount = intval($target->FragCount);
+ $this->playListName = strval($target->PlayListName);
+ }
+
+ public function serializeToXml()
+ {
+ $strXml = <<
+
+
+EOF;
+ $xml = new \SimpleXMLElement($strXml);
+ if (isset($this->description)) {
+ $xml->addChild('Description', $this->description);
+ }
+
+ if (isset($this->status)) {
+ $xml->addChild('Status', $this->status);
+ }
+
+ $node = $xml->addChild('Target');
+ $node->addChild('Type', $this->type);
+
+ if (isset($this->fragDuration)) {
+ $node->addChild('FragDuration', $this->fragDuration);
+ }
+
+ if (isset($this->fragCount)) {
+ $node->addChild('FragCount', $this->fragCount);
+ }
+
+ if (isset($this->playListName)) {
+ $node->addChild('PlayListName', $this->playListName);
+ }
+
+ return $xml->asXML();
+ }
+
+ public function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ private $description;
+ private $status = "enabled";
+ private $type;
+ private $fragDuration = 5;
+ private $fragCount = 3;
+ private $playListName = "playlist.m3u8";
+}
diff --git a/addons/alioss/library/OSS/Model/LiveChannelHistory.php b/addons/alioss/library/OSS/Model/LiveChannelHistory.php
new file mode 100644
index 0000000000000000000000000000000000000000..1c1fd4dbcdfa3b052bbf1bd61c04c73fcc279ddd
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/LiveChannelHistory.php
@@ -0,0 +1,59 @@
+startTime;
+ }
+
+ public function getEndTime()
+ {
+ return $this->endTime;
+ }
+
+ public function getRemoteAddr()
+ {
+ return $this->remoteAddr;
+ }
+
+ public function parseFromXmlNode($xml)
+ {
+ if (isset($xml->StartTime)) {
+ $this->startTime = strval($xml->StartTime);
+ }
+
+ if (isset($xml->EndTime)) {
+ $this->endTime = strval($xml->EndTime);
+ }
+
+ if (isset($xml->RemoteAddr)) {
+ $this->remoteAddr = strval($xml->RemoteAddr);
+ }
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ $this->parseFromXmlNode($xml);
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $startTime;
+ private $endTime;
+ private $remoteAddr;
+}
diff --git a/addons/alioss/library/OSS/Model/LiveChannelInfo.php b/addons/alioss/library/OSS/Model/LiveChannelInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..c63ec54d615171570a0351e4ee6b1d2b60e42fab
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/LiveChannelInfo.php
@@ -0,0 +1,107 @@
+name = $name;
+ $this->description = $description;
+ $this->publishUrls = array();
+ $this->playUrls = array();
+ }
+
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ public function setName($name)
+ {
+ $this->name = $name;
+ }
+
+ public function getPublishUrls()
+ {
+ return $this->publishUrls;
+ }
+
+ public function getPlayUrls()
+ {
+ return $this->playUrls;
+ }
+
+ public function getStatus()
+ {
+ return $this->status;
+ }
+
+ public function getLastModified()
+ {
+ return $this->lastModified;
+ }
+
+ public function getDescription()
+ {
+ return $this->description;
+ }
+
+ public function setDescription($description)
+ {
+ $this->description = $description;
+ }
+
+ public function parseFromXmlNode($xml)
+ {
+ if (isset($xml->Name)) {
+ $this->name = strval($xml->Name);
+ }
+
+ if (isset($xml->Description)) {
+ $this->description = strval($xml->Description);
+ }
+
+ if (isset($xml->Status)) {
+ $this->status = strval($xml->Status);
+ }
+
+ if (isset($xml->LastModified)) {
+ $this->lastModified = strval($xml->LastModified);
+ }
+
+ if (isset($xml->PublishUrls)) {
+ foreach ($xml->PublishUrls as $url) {
+ $this->publishUrls[] = strval($url->Url);
+ }
+ }
+
+ if (isset($xml->PlayUrls)) {
+ foreach ($xml->PlayUrls as $url) {
+ $this->playUrls[] = strval($url->Url);
+ }
+ }
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ $this->parseFromXmlNode($xml);
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $name;
+ private $description;
+ private $publishUrls;
+ private $playUrls;
+ private $status;
+ private $lastModified;
+}
diff --git a/addons/alioss/library/OSS/Model/LiveChannelListInfo.php b/addons/alioss/library/OSS/Model/LiveChannelListInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..bb5093aa8eb948675228c560bfd06d444df91cb4
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/LiveChannelListInfo.php
@@ -0,0 +1,107 @@
+bucket;
+ }
+
+ public function setBucketName($name)
+ {
+ $this->bucket = $name;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMarker()
+ {
+ return $this->marker;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxKeys()
+ {
+ return $this->maxKeys;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getIsTruncated()
+ {
+ return $this->isTruncated;
+ }
+
+ /**
+ * @return LiveChannelInfo[]
+ */
+ public function getChannelList()
+ {
+ return $this->channelList;
+ }
+
+ /**
+ * @return string
+ */
+ public function getNextMarker()
+ {
+ return $this->nextMarker;
+ }
+
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+
+ $this->prefix = strval($xml->Prefix);
+ $this->marker = strval($xml->Marker);
+ $this->maxKeys = intval($xml->MaxKeys);
+ $this->isTruncated = (strval($xml->IsTruncated) == 'true');
+ $this->nextMarker = strval($xml->NextMarker);
+
+ if (isset($xml->LiveChannel)) {
+ foreach ($xml->LiveChannel as $chan) {
+ $channel = new LiveChannelInfo();
+ $channel->parseFromXmlNode($chan);
+ $this->channelList[] = $channel;
+ }
+ }
+ }
+
+ public function serializeToXml()
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ private $bucket = '';
+ private $prefix = '';
+ private $marker = '';
+ private $nextMarker = '';
+ private $maxKeys = 100;
+ private $isTruncated = 'false';
+ private $channelList = array();
+}
diff --git a/addons/alioss/library/OSS/Model/LoggingConfig.php b/addons/alioss/library/OSS/Model/LoggingConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..978421a2504839422198cea5f7ea5517ae5bedcb
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/LoggingConfig.php
@@ -0,0 +1,86 @@
+targetBucket = $targetBucket;
+ $this->targetPrefix = $targetPrefix;
+ }
+
+ /**
+ * @param $strXml
+ * @return null
+ */
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ if (!isset($xml->LoggingEnabled)) return;
+ foreach ($xml->LoggingEnabled as $status) {
+ foreach ($status as $key => $value) {
+ if ($key === 'TargetBucket') {
+ $this->targetBucket = strval($value);
+ } elseif ($key === 'TargetPrefix') {
+ $this->targetPrefix = strval($value);
+ }
+ }
+ break;
+ }
+ }
+
+ /**
+ * 序列化成xml字符串
+ *
+ */
+ public function serializeToXml()
+ {
+ $xml = new \SimpleXMLElement(' ');
+ if (isset($this->targetBucket) && isset($this->targetPrefix)) {
+ $loggingEnabled = $xml->addChild('LoggingEnabled');
+ $loggingEnabled->addChild('TargetBucket', $this->targetBucket);
+ $loggingEnabled->addChild('TargetPrefix', $this->targetPrefix);
+ }
+ return $xml->asXML();
+ }
+
+ /**
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ /**
+ * @return string
+ */
+ public function getTargetBucket()
+ {
+ return $this->targetBucket;
+ }
+
+ /**
+ * @return string
+ */
+ public function getTargetPrefix()
+ {
+ return $this->targetPrefix;
+ }
+
+ private $targetBucket = "";
+ private $targetPrefix = "";
+
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/ObjectInfo.php b/addons/alioss/library/OSS/Model/ObjectInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..2ae6c99bd8ffcba68c04359c5438d05d10d4c369
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/ObjectInfo.php
@@ -0,0 +1,93 @@
+key = $key;
+ $this->lastModified = $lastModified;
+ $this->eTag = $eTag;
+ $this->type = $type;
+ $this->size = $size;
+ $this->storageClass = $storageClass;
+ }
+
+ /**
+ * @return string
+ */
+ public function getKey()
+ {
+ return $this->key;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLastModified()
+ {
+ return $this->lastModified;
+ }
+
+ /**
+ * @return string
+ */
+ public function getETag()
+ {
+ return $this->eTag;
+ }
+
+ /**
+ * @return string
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * @return int
+ */
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ /**
+ * @return string
+ */
+ public function getStorageClass()
+ {
+ return $this->storageClass;
+ }
+
+ private $key = "";
+ private $lastModified = "";
+ private $eTag = "";
+ private $type = "";
+ private $size = 0;
+ private $storageClass = "";
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/ObjectListInfo.php b/addons/alioss/library/OSS/Model/ObjectListInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..dbe7c7a7626ac9d22bdc8862815e66f3d6bfeac7
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/ObjectListInfo.php
@@ -0,0 +1,126 @@
+bucketName = $bucketName;
+ $this->prefix = $prefix;
+ $this->marker = $marker;
+ $this->nextMarker = $nextMarker;
+ $this->maxKeys = $maxKeys;
+ $this->delimiter = $delimiter;
+ $this->isTruncated = $isTruncated;
+ $this->objectList = $objectList;
+ $this->prefixList = $prefixList;
+ }
+
+ /**
+ * @return string
+ */
+ public function getBucketName()
+ {
+ return $this->bucketName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ /**
+ * @return string
+ */
+ public function getMarker()
+ {
+ return $this->marker;
+ }
+
+ /**
+ * @return int
+ */
+ public function getMaxKeys()
+ {
+ return $this->maxKeys;
+ }
+
+ /**
+ * @return string
+ */
+ public function getDelimiter()
+ {
+ return $this->delimiter;
+ }
+
+ /**
+ * @return mixed
+ */
+ public function getIsTruncated()
+ {
+ return $this->isTruncated;
+ }
+
+ /**
+ * 返回ListObjects接口返回数据中的ObjectInfo列表
+ *
+ * @return ObjectInfo[]
+ */
+ public function getObjectList()
+ {
+ return $this->objectList;
+ }
+
+ /**
+ * 返回ListObjects接口返回数据中的PrefixInfo列表
+ *
+ * @return PrefixInfo[]
+ */
+ public function getPrefixList()
+ {
+ return $this->prefixList;
+ }
+
+ /**
+ * @return string
+ */
+ public function getNextMarker()
+ {
+ return $this->nextMarker;
+ }
+
+ private $bucketName = "";
+ private $prefix = "";
+ private $marker = "";
+ private $nextMarker = "";
+ private $maxKeys = 0;
+ private $delimiter = "";
+ private $isTruncated = null;
+ private $objectList = array();
+ private $prefixList = array();
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/PartInfo.php b/addons/alioss/library/OSS/Model/PartInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..439a84d31634d3bf80477e912c02f36855fcbfcb
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/PartInfo.php
@@ -0,0 +1,63 @@
+partNumber = $partNumber;
+ $this->lastModified = $lastModified;
+ $this->eTag = $eTag;
+ $this->size = $size;
+ }
+
+ /**
+ * @return int
+ */
+ public function getPartNumber()
+ {
+ return $this->partNumber;
+ }
+
+ /**
+ * @return string
+ */
+ public function getLastModified()
+ {
+ return $this->lastModified;
+ }
+
+ /**
+ * @return string
+ */
+ public function getETag()
+ {
+ return $this->eTag;
+ }
+
+ /**
+ * @return int
+ */
+ public function getSize()
+ {
+ return $this->size;
+ }
+
+ private $partNumber = 0;
+ private $lastModified = "";
+ private $eTag = "";
+ private $size = 0;
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/PrefixInfo.php b/addons/alioss/library/OSS/Model/PrefixInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..e61eac4493f6294036699b3dafac0fc82440d76f
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/PrefixInfo.php
@@ -0,0 +1,36 @@
+prefix = $prefix;
+ }
+
+ /**
+ * @return string
+ */
+ public function getPrefix()
+ {
+ return $this->prefix;
+ }
+
+ private $prefix;
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/RefererConfig.php b/addons/alioss/library/OSS/Model/RefererConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..1d7d975c5873efd67ed1b03899d6932221498672
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/RefererConfig.php
@@ -0,0 +1,93 @@
+AllowEmptyReferer)) return;
+ if (!isset($xml->RefererList)) return;
+ $this->allowEmptyReferer =
+ (strval($xml->AllowEmptyReferer) === 'TRUE' || strval($xml->AllowEmptyReferer) === 'true') ? true : false;
+
+ foreach ($xml->RefererList->Referer as $key => $refer) {
+ $this->refererList[] = strval($refer);
+ }
+ }
+
+
+ /**
+ * 把RefererConfig序列化成xml
+ *
+ * @return string
+ */
+ public function serializeToXml()
+ {
+ $xml = new \SimpleXMLElement(' ');
+ if ($this->allowEmptyReferer) {
+ $xml->addChild('AllowEmptyReferer', 'true');
+ } else {
+ $xml->addChild('AllowEmptyReferer', 'false');
+ }
+ $refererList = $xml->addChild('RefererList');
+ foreach ($this->refererList as $referer) {
+ $refererList->addChild('Referer', $referer);
+ }
+ return $xml->asXML();
+ }
+
+ /**
+ * @return string
+ */
+ function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ /**
+ * @param boolean $allowEmptyReferer
+ */
+ public function setAllowEmptyReferer($allowEmptyReferer)
+ {
+ $this->allowEmptyReferer = $allowEmptyReferer;
+ }
+
+ /**
+ * @param string $referer
+ */
+ public function addReferer($referer)
+ {
+ $this->refererList[] = $referer;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isAllowEmptyReferer()
+ {
+ return $this->allowEmptyReferer;
+ }
+
+ /**
+ * @return array
+ */
+ public function getRefererList()
+ {
+ return $this->refererList;
+ }
+
+ private $allowEmptyReferer = true;
+ private $refererList = array();
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/StorageCapacityConfig.php b/addons/alioss/library/OSS/Model/StorageCapacityConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..05e6332c2cb9d432e73d67f472fe0ccd1ae5d599
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/StorageCapacityConfig.php
@@ -0,0 +1,74 @@
+storageCapacity = $storageCapacity;
+ }
+
+ /**
+ * Not implemented
+ */
+ public function parseFromXml($strXml)
+ {
+ throw new OssException("Not implemented.");
+ }
+
+ /**
+ * 把StorageCapacityConfig序列化成xml
+ *
+ * @return string
+ */
+ public function serializeToXml()
+ {
+ $xml = new \SimpleXMLElement(' ');
+ $xml->addChild('StorageCapacity', strval($this->storageCapacity));
+ return $xml->asXML();
+ }
+
+ /**
+ * To string
+ *
+ * @return string
+ */
+ function __toString()
+ {
+ return $this->serializeToXml();
+ }
+
+ /**
+ * Set storage capacity
+ *
+ * @param int $storageCapacity
+ */
+ public function setStorageCapacity($storageCapacity)
+ {
+ $this->storageCapacity = $storageCapacity;
+ }
+
+ /**
+ * Get storage capacity
+ *
+ * @return int
+ */
+ public function getStorageCapacity()
+ {
+ return $this->storageCapacity;
+ }
+
+ private $storageCapacity = 0;
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/UploadInfo.php b/addons/alioss/library/OSS/Model/UploadInfo.php
new file mode 100644
index 0000000000000000000000000000000000000000..8eaa3639fa8b76996d18f84b7a6a91d7e861ba86
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/UploadInfo.php
@@ -0,0 +1,55 @@
+key = $key;
+ $this->uploadId = $uploadId;
+ $this->initiated = $initiated;
+ }
+
+ /**
+ * @return string
+ */
+ public function getKey()
+ {
+ return $this->key;
+ }
+
+ /**
+ * @return string
+ */
+ public function getUploadId()
+ {
+ return $this->uploadId;
+ }
+
+ /**
+ * @return string
+ */
+ public function getInitiated()
+ {
+ return $this->initiated;
+ }
+
+ private $key = "";
+ private $uploadId = "";
+ private $initiated = "";
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/WebsiteConfig.php b/addons/alioss/library/OSS/Model/WebsiteConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..8ea08a030fff2a17ee603c3c8ae0b209d527c441
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/WebsiteConfig.php
@@ -0,0 +1,76 @@
+indexDocument = $indexDocument;
+ $this->errorDocument = $errorDocument;
+ }
+
+ /**
+ * @param string $strXml
+ * @return null
+ */
+ public function parseFromXml($strXml)
+ {
+ $xml = simplexml_load_string($strXml);
+ if (isset($xml->IndexDocument) && isset($xml->IndexDocument->Suffix)) {
+ $this->indexDocument = strval($xml->IndexDocument->Suffix);
+ }
+ if (isset($xml->ErrorDocument) && isset($xml->ErrorDocument->Key)) {
+ $this->errorDocument = strval($xml->ErrorDocument->Key);
+ }
+ }
+
+ /**
+ * 把WebsiteConfig序列化成xml
+ *
+ * @return string
+ * @throws OssException
+ */
+ public function serializeToXml()
+ {
+ $xml = new \SimpleXMLElement(' ');
+ $index_document_part = $xml->addChild('IndexDocument');
+ $error_document_part = $xml->addChild('ErrorDocument');
+ $index_document_part->addChild('Suffix', $this->indexDocument);
+ $error_document_part->addChild('Key', $this->errorDocument);
+ return $xml->asXML();
+ }
+
+ /**
+ * @return string
+ */
+ public function getIndexDocument()
+ {
+ return $this->indexDocument;
+ }
+
+ /**
+ * @return string
+ */
+ public function getErrorDocument()
+ {
+ return $this->errorDocument;
+ }
+
+ private $indexDocument = "";
+ private $errorDocument = "";
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Model/XmlConfig.php b/addons/alioss/library/OSS/Model/XmlConfig.php
new file mode 100644
index 0000000000000000000000000000000000000000..d353a2221b75fc3d4a1678ea92f6e624596cf62e
--- /dev/null
+++ b/addons/alioss/library/OSS/Model/XmlConfig.php
@@ -0,0 +1,27 @@
+hostname = $this->checkEndpoint($endpoint, $isCName);
+ $this->accessKeyId = $accessKeyId;
+ $this->accessKeySecret = $accessKeySecret;
+ $this->securityToken = $securityToken;
+ $this->requestProxy = $requestProxy;
+
+ self::checkEnv();
+ }
+
+ /**
+ * 列举用户所有的Bucket[GetService], Endpoint类型为cname不能进行此操作
+ *
+ * @param array $options
+ * @throws OssException
+ * @return BucketListInfo
+ */
+ public function listBuckets($options = NULL)
+ {
+ if ($this->hostType === self::OSS_HOST_TYPE_CNAME) {
+ throw new OssException("operation is not permitted with CName host");
+ }
+ $this->precheckOptions($options);
+ $options[self::OSS_BUCKET] = '';
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $response = $this->auth($options);
+ $result = new ListBucketsResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 创建bucket,默认创建的bucket的ACL是OssClient::OSS_ACL_TYPE_PRIVATE
+ *
+ * @param string $bucket
+ * @param string $acl
+ * @param array $options
+ * @param string $storageType
+ * @return null
+ */
+ public function createBucket($bucket, $acl = self::OSS_ACL_TYPE_PRIVATE, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_HEADERS] = array(self::OSS_ACL => $acl);
+ if (isset($options[self::OSS_STORAGE])) {
+ $this->precheckStorage($options[self::OSS_STORAGE]);
+ $options[self::OSS_CONTENT] = OssUtil::createBucketXmlBody($options[self::OSS_STORAGE]);
+ unset($options[self::OSS_STORAGE]);
+ }
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 删除bucket
+ * 如果Bucket不为空(Bucket中有Object,或者有分块上传的碎片),则Bucket无法删除,
+ * 必须删除Bucket中的所有Object以及碎片后,Bucket才能成功删除。
+ *
+ * @param string $bucket
+ * @param array $options
+ * @return null
+ */
+ public function deleteBucket($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = '/';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 判断bucket是否存在
+ *
+ * @param string $bucket
+ * @return bool
+ * @throws OssException
+ */
+ public function doesBucketExist($bucket)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'acl';
+ $response = $this->auth($options);
+ $result = new ExistResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取bucket所属的数据中心位置信息
+ *
+ * @param string $bucket
+ * @param array $options
+ * @throws OssException
+ * @return string
+ */
+ public function getBucketLocation($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'location';
+ $response = $this->auth($options);
+ $result = new GetLocationResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Bucket的Meta信息
+ *
+ * @param string $bucket
+ * @param array $options 具体参考SDK文档
+ * @return array
+ */
+ public function getBucketMeta($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD;
+ $options[self::OSS_OBJECT] = '/';
+ $response = $this->auth($options);
+ $result = new HeaderResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取bucket的ACL配置情况
+ *
+ * @param string $bucket
+ * @param array $options
+ * @throws OssException
+ * @return string
+ */
+ public function getBucketAcl($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'acl';
+ $response = $this->auth($options);
+ $result = new AclResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 设置bucket的ACL配置情况
+ *
+ * @param string $bucket bucket名称
+ * @param string $acl 读写权限,可选值 ['private', 'public-read', 'public-read-write']
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return null
+ */
+ public function putBucketAcl($bucket, $acl, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_HEADERS] = array(self::OSS_ACL => $acl);
+ $options[self::OSS_SUB_RESOURCE] = 'acl';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取object的ACL属性
+ *
+ * @param string $bucket
+ * @param string $object
+ * @throws OssException
+ * @return string
+ */
+ public function getObjectAcl($bucket, $object)
+ {
+ $options = array();
+ $this->precheckCommon($bucket, $object, $options, true);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_SUB_RESOURCE] = 'acl';
+ $response = $this->auth($options);
+ $result = new AclResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 设置object的ACL属性
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $acl 读写权限,可选值 ['default', 'private', 'public-read', 'public-read-write']
+ * @throws OssException
+ * @return null
+ */
+ public function putObjectAcl($bucket, $object, $acl)
+ {
+ $this->precheckCommon($bucket, $object, $options, true);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_ACL => $acl);
+ $options[self::OSS_SUB_RESOURCE] = 'acl';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Bucket的访问日志配置情况
+ *
+ * @param string $bucket bucket名称
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return LoggingConfig
+ */
+ public function getBucketLogging($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'logging';
+ $response = $this->auth($options);
+ $result = new GetLoggingResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 开启Bucket访问日志记录功能,只有Bucket的所有者才能更改
+ *
+ * @param string $bucket bucket名称
+ * @param string $targetBucket 日志文件存放的bucket
+ * @param string $targetPrefix 日志的文件前缀
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return null
+ */
+ public function putBucketLogging($bucket, $targetBucket, $targetPrefix, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $this->precheckBucket($targetBucket, 'targetbucket is not allowed empty');
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'logging';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+
+ $loggingConfig = new LoggingConfig($targetBucket, $targetPrefix);
+ $options[self::OSS_CONTENT] = $loggingConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 关闭bucket访问日志记录功能
+ *
+ * @param string $bucket bucket名称
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketLogging($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'logging';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 将bucket设置成静态网站托管模式
+ *
+ * @param string $bucket bucket名称
+ * @param WebsiteConfig $websiteConfig
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return null
+ */
+ public function putBucketWebsite($bucket, $websiteConfig, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'website';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $options[self::OSS_CONTENT] = $websiteConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取bucket的静态网站托管状态
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return WebsiteConfig
+ */
+ public function getBucketWebsite($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'website';
+ $response = $this->auth($options);
+ $result = new GetWebsiteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 关闭bucket的静态网站托管模式
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketWebsite($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'website';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 在指定的bucket上设定一个跨域资源共享(CORS)的规则,如果原规则存在则覆盖原规则
+ *
+ * @param string $bucket bucket名称
+ * @param CorsConfig $corsConfig 跨域资源共享配置,具体规则参见SDK文档
+ * @param array $options array
+ * @throws OssException
+ * @return null
+ */
+ public function putBucketCors($bucket, $corsConfig, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cors';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $options[self::OSS_CONTENT] = $corsConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Bucket的CORS配置情况
+ *
+ * @param string $bucket bucket名称
+ * @param array $options 可以为空
+ * @throws OssException
+ * @return CorsConfig
+ */
+ public function getBucketCors($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cors';
+ $response = $this->auth($options);
+ $result = new GetCorsResult($response, __FUNCTION__);
+ return $result->getData();
+ }
+
+ /**
+ * 关闭指定Bucket对应的CORS功能并清空所有规则
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketCors($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cors';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 为指定Bucket增加CNAME绑定
+ *
+ * @param string $bucket bucket名称
+ * @param string $cname
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function addBucketCname($bucket, $cname, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cname';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $cnameConfig = new CnameConfig();
+ $cnameConfig->addCname($cname);
+ $options[self::OSS_CONTENT] = $cnameConfig->serializeToXml();
+ $options[self::OSS_COMP] = 'add';
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取指定Bucket已绑定的CNAME列表
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return CnameConfig
+ */
+ public function getBucketCname($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cname';
+ $response = $this->auth($options);
+ $result = new GetCnameResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 解除指定Bucket的CNAME绑定
+ *
+ * @param string $bucket bucket名称
+ * @param CnameConfig $cnameConfig
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketCname($bucket, $cname, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'cname';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $cnameConfig = new CnameConfig();
+ $cnameConfig->addCname($cname);
+ $options[self::OSS_CONTENT] = $cnameConfig->serializeToXml();
+ $options[self::OSS_COMP] = 'delete';
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 为指定Bucket创建LiveChannel
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param LiveChannelConfig $channelConfig
+ * @param array $options
+ * @throws OssException
+ * @return LiveChannelInfo
+ */
+ public function putBucketLiveChannel($bucket, $channelName, $channelConfig, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $options[self::OSS_CONTENT] = $channelConfig->serializeToXml();
+
+ $response = $this->auth($options);
+ $result = new PutLiveChannelResult($response);
+ $info = $result->getData();
+ $info->setName($channelName);
+ $info->setDescription($channelConfig->getDescription());
+
+ return $info;
+ }
+
+ /**
+ * 设置LiveChannel的status
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param string channelStatus $channelStatus 为enabled或disabled
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function putLiveChannelStatus($bucket, $channelName, $channelStatus, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+ $options[self::OSS_LIVE_CHANNEL_STATUS] = $channelStatus;
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取LiveChannel信息
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param array $options
+ * @throws OssException
+ * @return GetLiveChannelInfo
+ */
+ public function getLiveChannelInfo($bucket, $channelName, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+
+ $response = $this->auth($options);
+ $result = new GetLiveChannelInfoResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取LiveChannel状态信息
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param array $options
+ * @throws OssException
+ * @return GetLiveChannelStatus
+ */
+ public function getLiveChannelStatus($bucket, $channelName, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+ $options[self::OSS_COMP] = 'stat';
+
+ $response = $this->auth($options);
+ $result = new GetLiveChannelStatusResult($response);
+ return $result->getData();
+ }
+
+ /**
+ *获取LiveChannel推流记录
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param array $options
+ * @throws OssException
+ * @return GetLiveChannelHistory
+ */
+ public function getLiveChannelHistory($bucket, $channelName, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+ $options[self::OSS_COMP] = 'history';
+
+ $response = $this->auth($options);
+ $result = new GetLiveChannelHistoryResult($response);
+ return $result->getData();
+ }
+
+ /**
+ *获取指定Bucket下的live channel列表
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return LiveChannelListInfo
+ */
+ public function listBucketLiveChannels($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+ $options[self::OSS_QUERY_STRING] = array(
+ 'prefix' => isset($options['prefix']) ? $options['prefix'] : '',
+ 'marker' => isset($options['marker']) ? $options['marker'] : '',
+ 'max-keys' => isset($options['max-keys']) ? $options['max-keys'] : '',
+ );
+ $response = $this->auth($options);
+ $result = new ListLiveChannelResult($response);
+ $list = $result->getData();
+ $list->setBucketName($bucket);
+
+ return $list;
+ }
+
+ /**
+ * 为指定LiveChannel生成播放列表
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param string $playlistName 指定生成的点播播放列表的名称,必须以“.m3u8”结尾
+ * @param array $setTime startTime和EndTime以unix时间戳格式给定,跨度不能超过一天
+ * @throws OssException
+ * @return null
+ */
+ public function postVodPlaylist($bucket, $channelName, $playlistName, $setTime)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_OBJECT] = $channelName . '/' . $playlistName;
+ $options[self::OSS_SUB_RESOURCE] = 'vod';
+ $options[self::OSS_LIVE_CHANNEL_END_TIME] = $setTime['EndTime'];
+ $options[self::OSS_LIVE_CHANNEL_START_TIME] = $setTime['StartTime'];
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 删除指定Bucket的LiveChannel
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketLiveChannel($bucket, $channelName, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = $channelName;
+ $options[self::OSS_SUB_RESOURCE] = 'live';
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 生成带签名的推流地址
+ *
+ * @param string $bucket bucket名称
+ * @param string channelName $channelName
+ * @param int timeout 设置超时时间,单位为秒
+ * @param array $options
+ * @throws OssException
+ * @return 推流地址
+ */
+ public function signRtmpUrl($bucket, $channelName, $timeout = 60, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $channelName, $options, false);
+ $expires = time() + $timeout;
+ $proto = 'rtmp://';
+ $hostname = $this->generateHostname($bucket);
+ $cano_params = '';
+ $query_items = array();
+ $params = isset($options['params']) ? $options['params'] : array();
+ uksort($params, 'strnatcasecmp');
+ foreach ($params as $key => $value) {
+ $cano_params = $cano_params . $key . ':' . $value . "\n";
+ $query_items[] = rawurlencode($key) . '=' . rawurlencode($value);
+ }
+ $resource = '/' . $bucket . '/' . $channelName;
+
+ $string_to_sign = $expires . "\n" . $cano_params . $resource;
+ $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $this->accessKeySecret, true));
+
+ $query_items[] = 'OSSAccessKeyId=' . rawurlencode($this->accessKeyId);
+ $query_items[] = 'Expires=' . rawurlencode($expires);
+ $query_items[] = 'Signature=' . rawurlencode($signature);
+
+ return $proto . $hostname . '/live/' . $channelName . '?' . implode('&', $query_items);
+ }
+
+ /**
+ * 检验跨域资源请求, 发送跨域请求之前会发送一个preflight请求(OPTIONS)并带上特定的来源域,
+ * HTTP方法和header信息等给OSS以决定是否发送真正的请求。 OSS可以通过putBucketCors接口
+ * 来开启Bucket的CORS支持,开启CORS功能之后,OSS在收到浏览器preflight请求时会根据设定的
+ * 规则评估是否允许本次请求
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $origin 请求来源域
+ * @param string $request_method 表明实际请求中会使用的HTTP方法
+ * @param string $request_headers 表明实际请求中会使用的除了简单头部之外的headers
+ * @param array $options
+ * @return array
+ * @throws OssException
+ * @link http://help.aliyun.com/document_detail/oss/api-reference/cors/OptionObject.html
+ */
+ public function optionsObject($bucket, $object, $origin, $request_method, $request_headers, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_OPTIONS;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_HEADERS] = array(
+ self::OSS_OPTIONS_ORIGIN => $origin,
+ self::OSS_OPTIONS_REQUEST_HEADERS => $request_headers,
+ self::OSS_OPTIONS_REQUEST_METHOD => $request_method
+ );
+ $response = $this->auth($options);
+ $result = new HeaderResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 设置Bucket的Lifecycle配置
+ *
+ * @param string $bucket bucket名称
+ * @param LifecycleConfig $lifecycleConfig Lifecycle配置类
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function putBucketLifecycle($bucket, $lifecycleConfig, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'lifecycle';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $options[self::OSS_CONTENT] = $lifecycleConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Bucket的Lifecycle配置情况
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return LifecycleConfig
+ */
+ public function getBucketLifecycle($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'lifecycle';
+ $response = $this->auth($options);
+ $result = new GetLifecycleResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 删除指定Bucket的生命周期配置
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return null
+ */
+ public function deleteBucketLifecycle($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'lifecycle';
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 设置一个bucket的referer访问白名单和是否允许referer字段为空的请求访问
+ * Bucket Referer防盗链具体见OSS防盗链
+ *
+ * @param string $bucket bucket名称
+ * @param RefererConfig $refererConfig
+ * @param array $options
+ * @return ResponseCore
+ * @throws null
+ */
+ public function putBucketReferer($bucket, $refererConfig, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'referer';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $options[self::OSS_CONTENT] = $refererConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Bucket的Referer配置情况
+ * Bucket Referer防盗链具体见OSS防盗链
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return RefererConfig
+ */
+ public function getBucketReferer($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'referer';
+ $response = $this->auth($options);
+ $result = new GetRefererResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 设置bucket的容量大小,单位GB
+ * 当bucket的容量大于设置的容量时,禁止继续写入
+ *
+ * @param string $bucket bucket名称
+ * @param int $storageCapacity
+ * @param array $options
+ * @return ResponseCore
+ * @throws null
+ */
+ public function putBucketStorageCapacity($bucket, $storageCapacity, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'qos';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $storageCapacityConfig = new StorageCapacityConfig($storageCapacity);
+ $options[self::OSS_CONTENT] = $storageCapacityConfig->serializeToXml();
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取bucket的容量大小,单位GB
+ *
+ * @param string $bucket bucket名称
+ * @param array $options
+ * @throws OssException
+ * @return int
+ */
+ public function getBucketStorageCapacity($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'qos';
+ $response = $this->auth($options);
+ $result = new GetStorageCapacityResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取bucket下的object列表
+ *
+ * @param string $bucket
+ * @param array $options
+ * 其中options中的参数如下
+ * $options = array(
+ * 'max-keys' => max-keys用于限定此次返回object的最大数,如果不设定,默认为100,max-keys取值不能大于1000。
+ * 'prefix' => 限定返回的object key必须以prefix作为前缀。注意使用prefix查询时,返回的key中仍会包含prefix。
+ * 'delimiter' => 是一个用于对Object名字进行分组的字符。所有名字包含指定的前缀且第一次出现delimiter字符之间的object作为一组元素
+ * 'marker' => 用户设定结果从marker之后按字母排序的第一个开始返回。
+ * )
+ * 其中 prefix,marker用来实现分页显示效果,参数的长度必须小于256字节。
+ * @throws OssException
+ * @return ObjectListInfo
+ */
+ public function listObjects($bucket, $options = NULL)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_HEADERS] = array(
+ self::OSS_DELIMITER => isset($options[self::OSS_DELIMITER]) ? $options[self::OSS_DELIMITER] : '/',
+ self::OSS_PREFIX => isset($options[self::OSS_PREFIX]) ? $options[self::OSS_PREFIX] : '',
+ self::OSS_MAX_KEYS => isset($options[self::OSS_MAX_KEYS]) ? $options[self::OSS_MAX_KEYS] : self::OSS_MAX_KEYS_VALUE,
+ self::OSS_MARKER => isset($options[self::OSS_MARKER]) ? $options[self::OSS_MARKER] : '',
+ );
+ $query = isset($options[self::OSS_QUERY_STRING]) ? $options[self::OSS_QUERY_STRING] : array();
+ $options[self::OSS_QUERY_STRING] = array_merge(
+ $query,
+ array(self::OSS_ENCODING_TYPE => self::OSS_ENCODING_TYPE_URL)
+ );
+
+ $response = $this->auth($options);
+ $result = new ListObjectsResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 创建虚拟目录 (本函数会在object名称后增加'/', 所以创建目录的object名称不需要'/'结尾,否则,目录名称会变成'//')
+ *
+ * 暂不开放此接口
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param array $options
+ * @return null
+ */
+ public function createObjectDir($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $object . '/';
+ $options[self::OSS_CONTENT_LENGTH] = array(self::OSS_CONTENT_LENGTH => 0);
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 上传内存中的内容
+ *
+ * @param string $bucket bucket名称
+ * @param string $object objcet名称
+ * @param string $content 上传的内容
+ * @param array $options
+ * @return null
+ */
+ public function putObject($bucket, $object, $content, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+
+ $options[self::OSS_CONTENT] = $content;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $object;
+
+ if (!isset($options[self::OSS_LENGTH])) {
+ $options[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]);
+ } else {
+ $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];
+ }
+
+ $is_check_md5 = $this->isCheckMD5($options);
+ if ($is_check_md5) {
+ $content_md5 = base64_encode(md5($content, true));
+ $options[self::OSS_CONTENT_MD5] = $content_md5;
+ }
+
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object);
+ }
+ $response = $this->auth($options);
+
+ if (isset($options[self::OSS_CALLBACK]) && !empty($options[self::OSS_CALLBACK])) {
+ $result = new CallbackResult($response);
+ } else {
+ $result = new PutSetDeleteResult($response);
+ }
+
+ return $result->getData();
+ }
+
+ /**
+ * 创建symlink
+ * @param string $bucket bucket名称
+ * @param string $symlink symlink名称
+ * @param string $targetObject 目标object名称
+ * @param array $options
+ * @return null
+ */
+ public function putSymlink($bucket, $symlink, $targetObject, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $symlink, $options);
+
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $symlink;
+ $options[self::OSS_SUB_RESOURCE] = self::OSS_SYMLINK;
+ $options[self::OSS_HEADERS][self::OSS_SYMLINK_TARGET] = rawurlencode($targetObject);
+
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取symlink
+ * @param string $bucket bucket名称
+ * @param string $symlink symlink名称
+ * @return null
+ */
+ public function getSymlink($bucket, $symlink)
+ {
+ $this->precheckCommon($bucket, $symlink, $options);
+
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = $symlink;
+ $options[self::OSS_SUB_RESOURCE] = self::OSS_SYMLINK;
+
+ $response = $this->auth($options);
+ $result = new SymlinkResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 上传本地文件
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $file 本地文件路径
+ * @param array $options
+ * @return null
+ * @throws OssException
+ */
+ public function uploadFile($bucket, $object, $file, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ OssUtil::throwOssExceptionWithMessageIfEmpty($file, "file path is invalid");
+ $file = OssUtil::encodePath($file);
+ if (!file_exists($file)) {
+ throw new OssException($file . " file does not exist");
+ }
+ $options[self::OSS_FILE_UPLOAD] = $file;
+ $file_size = filesize($options[self::OSS_FILE_UPLOAD]);
+ $is_check_md5 = $this->isCheckMD5($options);
+ if ($is_check_md5) {
+ $content_md5 = base64_encode(md5_file($options[self::OSS_FILE_UPLOAD], true));
+ $options[self::OSS_CONTENT_MD5] = $content_md5;
+ }
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $file);
+ }
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_CONTENT_LENGTH] = $file_size;
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 追加上传内存中的内容
+ *
+ * @param string $bucket bucket名称
+ * @param string $object objcet名称
+ * @param string $content 本次追加上传的内容
+ * @param array $options
+ * @return int next append position
+ * @throws OssException
+ */
+ public function appendObject($bucket, $object, $content, $position, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+
+ $options[self::OSS_CONTENT] = $content;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_SUB_RESOURCE] = 'append';
+ $options[self::OSS_POSITION] = strval($position);
+
+ if (!isset($options[self::OSS_LENGTH])) {
+ $options[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]);
+ } else {
+ $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];
+ }
+
+ $is_check_md5 = $this->isCheckMD5($options);
+ if ($is_check_md5) {
+ $content_md5 = base64_encode(md5($content, true));
+ $options[self::OSS_CONTENT_MD5] = $content_md5;
+ }
+
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object);
+ }
+ $response = $this->auth($options);
+ $result = new AppendResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 追加上传本地文件
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $file 追加上传的本地文件路径
+ * @param array $options
+ * @return int next append position
+ * @throws OssException
+ */
+ public function appendFile($bucket, $object, $file, $position, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+
+ OssUtil::throwOssExceptionWithMessageIfEmpty($file, "file path is invalid");
+ $file = OssUtil::encodePath($file);
+ if (!file_exists($file)) {
+ throw new OssException($file . " file does not exist");
+ }
+ $options[self::OSS_FILE_UPLOAD] = $file;
+ $file_size = filesize($options[self::OSS_FILE_UPLOAD]);
+ $is_check_md5 = $this->isCheckMD5($options);
+ if ($is_check_md5) {
+ $content_md5 = base64_encode(md5_file($options[self::OSS_FILE_UPLOAD], true));
+ $options[self::OSS_CONTENT_MD5] = $content_md5;
+ }
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $file);
+ }
+
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_CONTENT_LENGTH] = $file_size;
+ $options[self::OSS_SUB_RESOURCE] = 'append';
+ $options[self::OSS_POSITION] = strval($position);
+
+ $response = $this->auth($options);
+ $result = new AppendResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 拷贝一个在OSS上已经存在的object成另外一个object
+ *
+ * @param string $fromBucket 源bucket名称
+ * @param string $fromObject 源object名称
+ * @param string $toBucket 目标bucket名称
+ * @param string $toObject 目标object名称
+ * @param array $options
+ * @return null
+ * @throws OssException
+ */
+ public function copyObject($fromBucket, $fromObject, $toBucket, $toObject, $options = NULL)
+ {
+ $this->precheckCommon($fromBucket, $fromObject, $options);
+ $this->precheckCommon($toBucket, $toObject, $options);
+ $options[self::OSS_BUCKET] = $toBucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_OBJECT] = $toObject;
+ if (isset($options[self::OSS_HEADERS])) {
+ $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE] = '/' . $fromBucket . '/' . $fromObject;
+ } else {
+ $options[self::OSS_HEADERS] = array(self::OSS_OBJECT_COPY_SOURCE => '/' . $fromBucket . '/' . $fromObject);
+ }
+ $response = $this->auth($options);
+ $result = new CopyObjectResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取Object的Meta信息
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $options 具体参考SDK文档
+ * @return array
+ */
+ public function getObjectMeta($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD;
+ $options[self::OSS_OBJECT] = $object;
+ $response = $this->auth($options);
+ $result = new HeaderResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 删除某个Object
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param array $options
+ * @return null
+ */
+ public function deleteObject($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_OBJECT] = $object;
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 删除同一个Bucket中的多个Object
+ *
+ * @param string $bucket bucket名称
+ * @param array $objects object列表
+ * @param array $options
+ * @return ResponseCore
+ * @throws null
+ */
+ public function deleteObjects($bucket, $objects, $options = null)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ if (!is_array($objects) || !$objects) {
+ throw new OssException('objects must be array');
+ }
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'delete';
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ $quiet = 'false';
+ if (isset($options['quiet'])) {
+ if (is_bool($options['quiet'])) { //Boolean
+ $quiet = $options['quiet'] ? 'true' : 'false';
+ } elseif (is_string($options['quiet'])) { // string
+ $quiet = ($options['quiet'] === 'true') ? 'true' : 'false';
+ }
+ }
+ $xmlBody = OssUtil::createDeleteObjectsXmlBody($objects, $quiet);
+ $options[self::OSS_CONTENT] = $xmlBody;
+ $response = $this->auth($options);
+ $result = new DeleteObjectsResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获得Object内容
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param array $options 该参数中必须设置ALIOSS::OSS_FILE_DOWNLOAD,ALIOSS::OSS_RANGE可选,可以根据实际情况设置;如果不设置,默认会下载全部内容
+ * @return string
+ */
+ public function getObject($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_OBJECT] = $object;
+ if (isset($options[self::OSS_LAST_MODIFIED])) {
+ $options[self::OSS_HEADERS][self::OSS_IF_MODIFIED_SINCE] = $options[self::OSS_LAST_MODIFIED];
+ unset($options[self::OSS_LAST_MODIFIED]);
+ }
+ if (isset($options[self::OSS_ETAG])) {
+ $options[self::OSS_HEADERS][self::OSS_IF_NONE_MATCH] = $options[self::OSS_ETAG];
+ unset($options[self::OSS_ETAG]);
+ }
+ if (isset($options[self::OSS_RANGE])) {
+ $range = $options[self::OSS_RANGE];
+ $options[self::OSS_HEADERS][self::OSS_RANGE] = "bytes=$range";
+ unset($options[self::OSS_RANGE]);
+ }
+ $response = $this->auth($options);
+ $result = new BodyResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 检测Object是否存在
+ * 通过获取Object的Meta信息来判断Object是否存在, 用户需要自行解析ResponseCore判断object是否存在
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param array $options
+ * @return bool
+ */
+ public function doesObjectExist($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_HEAD;
+ $options[self::OSS_OBJECT] = $object;
+ $response = $this->auth($options);
+ $result = new ExistResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 针对Archive类型的Object读取
+ * 需要使用Restore操作让服务端执行解冻任务
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @return null
+ * @throws OssException
+ */
+ public function restoreObject($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_SUB_RESOURCE] = self::OSS_RESTORE;
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取分片大小,根据用户提供的part_size,重新计算一个更合理的partsize
+ *
+ * @param int $partSize
+ * @return int
+ */
+ private function computePartSize($partSize)
+ {
+ $partSize = (integer)$partSize;
+ if ($partSize <= self::OSS_MIN_PART_SIZE) {
+ $partSize = self::OSS_MIN_PART_SIZE;
+ } elseif ($partSize > self::OSS_MAX_PART_SIZE) {
+ $partSize = self::OSS_MAX_PART_SIZE;
+ }
+ return $partSize;
+ }
+
+ /**
+ * 计算文件可以分成多少个part,以及每个part的长度以及起始位置
+ * 方法必须在 中调用
+ *
+ * @param integer $file_size 文件大小
+ * @param integer $partSize part大小,默认5M
+ * @return array An array 包含 key-value 键值对. Key 为 `seekTo` 和 `length`.
+ */
+ public function generateMultiuploadParts($file_size, $partSize = 5242880)
+ {
+ $i = 0;
+ $size_count = $file_size;
+ $values = array();
+ $partSize = $this->computePartSize($partSize);
+ while ($size_count > 0) {
+ $size_count -= $partSize;
+ $values[] = array(
+ self::OSS_SEEK_TO => ($partSize * $i),
+ self::OSS_LENGTH => (($size_count > 0) ? $partSize : ($size_count + $partSize)),
+ );
+ $i++;
+ }
+ return $values;
+ }
+
+ /**
+ * 初始化multi-part upload
+ *
+ * @param string $bucket Bucket名称
+ * @param string $object Object名称
+ * @param array $options Key-Value数组
+ * @throws OssException
+ * @return string 返回uploadid
+ */
+ public function initiateMultipartUpload($bucket, $object, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_SUB_RESOURCE] = 'uploads';
+ $options[self::OSS_CONTENT] = '';
+
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object);
+ }
+ if (!isset($options[self::OSS_HEADERS])) {
+ $options[self::OSS_HEADERS] = array();
+ }
+ $response = $this->auth($options);
+ $result = new InitiateMultipartUploadResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 分片上传的块上传接口
+ *
+ * @param string $bucket Bucket名称
+ * @param string $object Object名称
+ * @param string $uploadId
+ * @param array $options Key-Value数组
+ * @return string eTag
+ * @throws OssException
+ */
+ public function uploadPart($bucket, $object, $uploadId, $options = null)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $this->precheckParam($options, self::OSS_FILE_UPLOAD, __FUNCTION__);
+ $this->precheckParam($options, self::OSS_PART_NUM, __FUNCTION__);
+
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_UPLOAD_ID] = $uploadId;
+
+ if (isset($options[self::OSS_LENGTH])) {
+ $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];
+ }
+ $response = $this->auth($options);
+ $result = new UploadPartResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 获取已成功上传的part
+ *
+ * @param string $bucket Bucket名称
+ * @param string $object Object名称
+ * @param string $uploadId uploadId
+ * @param array $options Key-Value数组
+ * @return ListPartsInfo
+ * @throws OssException
+ */
+ public function listParts($bucket, $object, $uploadId, $options = null)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_UPLOAD_ID] = $uploadId;
+ $options[self::OSS_QUERY_STRING] = array();
+ foreach (array('max-parts', 'part-number-marker') as $param) {
+ if (isset($options[$param])) {
+ $options[self::OSS_QUERY_STRING][$param] = $options[$param];
+ unset($options[$param]);
+ }
+ }
+ $response = $this->auth($options);
+ $result = new ListPartsResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 中止进行一半的分片上传操作
+ *
+ * @param string $bucket Bucket名称
+ * @param string $object Object名称
+ * @param string $uploadId uploadId
+ * @param array $options Key-Value数组
+ * @return null
+ * @throws OssException
+ */
+ public function abortMultipartUpload($bucket, $object, $uploadId, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_DELETE;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_UPLOAD_ID] = $uploadId;
+ $response = $this->auth($options);
+ $result = new PutSetDeleteResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 在将所有数据Part都上传完成后,调用此接口完成本次分块上传
+ *
+ * @param string $bucket Bucket名称
+ * @param string $object Object名称
+ * @param string $uploadId uploadId
+ * @param array $listParts array( array("PartNumber"=> int, "ETag"=>string))
+ * @param array $options Key-Value数组
+ * @throws OssException
+ * @return null
+ */
+ public function completeMultipartUpload($bucket, $object, $uploadId, $listParts, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_POST;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_UPLOAD_ID] = $uploadId;
+ $options[self::OSS_CONTENT_TYPE] = 'application/xml';
+ if (!is_array($listParts)) {
+ throw new OssException("listParts must be array type");
+ }
+ $options[self::OSS_CONTENT] = OssUtil::createCompleteMultipartUploadXmlBody($listParts);
+ $response = $this->auth($options);
+ if (isset($options[self::OSS_CALLBACK]) && !empty($options[self::OSS_CALLBACK])) {
+ $result = new CallbackResult($response);
+ } else {
+ $result = new PutSetDeleteResult($response);
+ }
+ return $result->getData();
+ }
+
+ /**
+ * 罗列出所有执行中的Multipart Upload事件,即已经被初始化的Multipart Upload但是未被
+ * Complete或者Abort的Multipart Upload事件
+ *
+ * @param string $bucket bucket
+ * @param array $options 关联数组
+ * @throws OssException
+ * @return ListMultipartUploadInfo
+ */
+ public function listMultipartUploads($bucket, $options = null)
+ {
+ $this->precheckCommon($bucket, NULL, $options, false);
+ $options[self::OSS_METHOD] = self::OSS_HTTP_GET;
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = '/';
+ $options[self::OSS_SUB_RESOURCE] = 'uploads';
+
+ foreach (array('delimiter', 'key-marker', 'max-uploads', 'prefix', 'upload-id-marker') as $param) {
+ if (isset($options[$param])) {
+ $options[self::OSS_QUERY_STRING][$param] = $options[$param];
+ unset($options[$param]);
+ }
+ }
+ $query = isset($options[self::OSS_QUERY_STRING]) ? $options[self::OSS_QUERY_STRING] : array();
+ $options[self::OSS_QUERY_STRING] = array_merge(
+ $query,
+ array(self::OSS_ENCODING_TYPE => self::OSS_ENCODING_TYPE_URL)
+ );
+
+ $response = $this->auth($options);
+ $result = new ListMultipartUploadResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * 从一个已存在的Object中拷贝数据来上传一个Part
+ *
+ * @param string $fromBucket 源bucket名称
+ * @param string $fromObject 源object名称
+ * @param string $toBucket 目标bucket名称
+ * @param string $toObject 目标object名称
+ * @param int $partNumber 分块上传的块id
+ * @param string $uploadId 初始化multipart upload返回的uploadid
+ * @param array $options Key-Value数组
+ * @return null
+ * @throws OssException
+ */
+ public function uploadPartCopy($fromBucket, $fromObject, $toBucket, $toObject, $partNumber, $uploadId, $options = NULL)
+ {
+ $this->precheckCommon($fromBucket, $fromObject, $options);
+ $this->precheckCommon($toBucket, $toObject, $options);
+
+ //如果没有设置$options['isFullCopy'],则需要强制判断copy的起止位置
+ $start_range = "0";
+ if (isset($options['start'])) {
+ $start_range = $options['start'];
+ }
+ $end_range = "";
+ if (isset($options['end'])) {
+ $end_range = $options['end'];
+ }
+ $options[self::OSS_METHOD] = self::OSS_HTTP_PUT;
+ $options[self::OSS_BUCKET] = $toBucket;
+ $options[self::OSS_OBJECT] = $toObject;
+ $options[self::OSS_PART_NUM] = $partNumber;
+ $options[self::OSS_UPLOAD_ID] = $uploadId;
+
+ if (!isset($options[self::OSS_HEADERS])) {
+ $options[self::OSS_HEADERS] = array();
+ }
+
+ $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE] = '/' . $fromBucket . '/' . $fromObject;
+ $options[self::OSS_HEADERS][self::OSS_OBJECT_COPY_SOURCE_RANGE] = "bytes=" . $start_range . "-" . $end_range;
+ $response = $this->auth($options);
+ $result = new UploadPartResult($response);
+ return $result->getData();
+ }
+
+ /**
+ * multipart上传统一封装,从初始化到完成multipart,以及出错后中止动作
+ *
+ * @param string $bucket bucket名称
+ * @param string $object object名称
+ * @param string $file 需要上传的本地文件的路径
+ * @param array $options Key-Value数组
+ * @return null
+ * @throws OssException
+ */
+ public function multiuploadFile($bucket, $object, $file, $options = null)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ if (isset($options[self::OSS_LENGTH])) {
+ $options[self::OSS_CONTENT_LENGTH] = $options[self::OSS_LENGTH];
+ unset($options[self::OSS_LENGTH]);
+ }
+ if (empty($file)) {
+ throw new OssException("parameter invalid, file is empty");
+ }
+ $uploadFile = OssUtil::encodePath($file);
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = $this->getMimeType($object, $uploadFile);
+ }
+
+ $upload_position = isset($options[self::OSS_SEEK_TO]) ? (integer)$options[self::OSS_SEEK_TO] : 0;
+
+ if (isset($options[self::OSS_CONTENT_LENGTH])) {
+ $upload_file_size = (integer)$options[self::OSS_CONTENT_LENGTH];
+ } else {
+ $upload_file_size = filesize($uploadFile);
+ if ($upload_file_size !== false) {
+ $upload_file_size -= $upload_position;
+ }
+ }
+
+ if ($upload_position === false || !isset($upload_file_size) || $upload_file_size === false || $upload_file_size < 0) {
+ throw new OssException('The size of `fileUpload` cannot be determined in ' . __FUNCTION__ . '().');
+ }
+ // 处理partSize
+ if (isset($options[self::OSS_PART_SIZE])) {
+ $options[self::OSS_PART_SIZE] = $this->computePartSize($options[self::OSS_PART_SIZE]);
+ } else {
+ $options[self::OSS_PART_SIZE] = self::OSS_MID_PART_SIZE;
+ }
+
+ $is_check_md5 = $this->isCheckMD5($options);
+ // 如果上传的文件小于partSize,则直接使用普通方式上传
+ if ($upload_file_size < $options[self::OSS_PART_SIZE] && !isset($options[self::OSS_UPLOAD_ID])) {
+ return $this->uploadFile($bucket, $object, $uploadFile, $options);
+ }
+
+ // 初始化multipart
+ if (isset($options[self::OSS_UPLOAD_ID])) {
+ $uploadId = $options[self::OSS_UPLOAD_ID];
+ } else {
+ // 初始化
+ $uploadId = $this->initiateMultipartUpload($bucket, $object, $options);
+ }
+
+ // 获取的分片
+ $pieces = $this->generateMultiuploadParts($upload_file_size, (integer)$options[self::OSS_PART_SIZE]);
+ $response_upload_part = array();
+ foreach ($pieces as $i => $piece) {
+ $from_pos = $upload_position + (integer)$piece[self::OSS_SEEK_TO];
+ $to_pos = (integer)$piece[self::OSS_LENGTH] + $from_pos - 1;
+ $up_options = array(
+ self::OSS_FILE_UPLOAD => $uploadFile,
+ self::OSS_PART_NUM => ($i + 1),
+ self::OSS_SEEK_TO => $from_pos,
+ self::OSS_LENGTH => $to_pos - $from_pos + 1,
+ self::OSS_CHECK_MD5 => $is_check_md5,
+ );
+ if ($is_check_md5) {
+ $content_md5 = OssUtil::getMd5SumForFile($uploadFile, $from_pos, $to_pos);
+ $up_options[self::OSS_CONTENT_MD5] = $content_md5;
+ }
+ $response_upload_part[] = $this->uploadPart($bucket, $object, $uploadId, $up_options);
+ }
+
+ $uploadParts = array();
+ foreach ($response_upload_part as $i => $etag) {
+ $uploadParts[] = array(
+ 'PartNumber' => ($i + 1),
+ 'ETag' => $etag,
+ );
+ }
+ return $this->completeMultipartUpload($bucket, $object, $uploadId, $uploadParts);
+ }
+
+ /**
+ * 上传本地目录内的文件或者目录到指定bucket的指定prefix的object中
+ *
+ * @param string $bucket bucket名称
+ * @param string $prefix 需要上传到的object的key前缀,可以理解成bucket中的子目录,结尾不能是'/',接口中会补充'/'
+ * @param string $localDirectory 需要上传的本地目录
+ * @param string $exclude 需要排除的目录
+ * @param bool $recursive 是否递归的上传localDirectory下的子目录内容
+ * @param bool $checkMd5
+ * @return array 返回两个列表 array("succeededList" => array("object"), "failedList" => array("object"=>"errorMessage"))
+ * @throws OssException
+ */
+ public function uploadDir($bucket, $prefix, $localDirectory, $exclude = '.|..|.svn|.git', $recursive = false, $checkMd5 = true)
+ {
+ $retArray = array("succeededList" => array(), "failedList" => array());
+ if (empty($bucket)) throw new OssException("parameter error, bucket is empty");
+ if (!is_string($prefix)) throw new OssException("parameter error, prefix is not string");
+ if (empty($localDirectory)) throw new OssException("parameter error, localDirectory is empty");
+ $directory = $localDirectory;
+ $directory = OssUtil::encodePath($directory);
+ //判断是否目录
+ if (!is_dir($directory)) {
+ throw new OssException('parameter error: ' . $directory . ' is not a directory, please check it');
+ }
+ //read directory
+ $file_list_array = OssUtil::readDir($directory, $exclude, $recursive);
+ if (!$file_list_array) {
+ throw new OssException($directory . ' is empty...');
+ }
+ foreach ($file_list_array as $k => $item) {
+ if (is_dir($item['path'])) {
+ continue;
+ }
+ $options = array(
+ self::OSS_PART_SIZE => self::OSS_MIN_PART_SIZE,
+ self::OSS_CHECK_MD5 => $checkMd5,
+ );
+ $realObject = (!empty($prefix) ? $prefix . '/' : '') . $item['file'];
+
+ try {
+ $this->multiuploadFile($bucket, $realObject, $item['path'], $options);
+ $retArray["succeededList"][] = $realObject;
+ } catch (OssException $e) {
+ $retArray["failedList"][$realObject] = $e->getMessage();
+ }
+ }
+ return $retArray;
+ }
+
+ /**
+ * 支持生成get和put签名, 用户可以生成一个具有一定有效期的
+ * 签名过的url
+ *
+ * @param string $bucket
+ * @param string $object
+ * @param int $timeout
+ * @param string $method
+ * @param array $options Key-Value数组
+ * @return string
+ * @throws OssException
+ */
+ public function signUrl($bucket, $object, $timeout = 60, $method = self::OSS_HTTP_GET, $options = NULL)
+ {
+ $this->precheckCommon($bucket, $object, $options);
+ //method
+ if (self::OSS_HTTP_GET !== $method && self::OSS_HTTP_PUT !== $method) {
+ throw new OssException("method is invalid");
+ }
+ $options[self::OSS_BUCKET] = $bucket;
+ $options[self::OSS_OBJECT] = $object;
+ $options[self::OSS_METHOD] = $method;
+ if (!isset($options[self::OSS_CONTENT_TYPE])) {
+ $options[self::OSS_CONTENT_TYPE] = '';
+ }
+ $timeout = time() + $timeout;
+ $options[self::OSS_PREAUTH] = $timeout;
+ $options[self::OSS_DATE] = $timeout;
+ $this->setSignStsInUrl(true);
+ return $this->auth($options);
+ }
+
+ /**
+ * 检测options参数
+ *
+ * @param array $options
+ * @throws OssException
+ */
+ private function precheckOptions(&$options)
+ {
+ OssUtil::validateOptions($options);
+ if (!$options) {
+ $options = array();
+ }
+ }
+
+ /**
+ * 校验bucket参数
+ *
+ * @param string $bucket
+ * @param string $errMsg
+ * @throws OssException
+ */
+ private function precheckBucket($bucket, $errMsg = 'bucket is not allowed empty')
+ {
+ OssUtil::throwOssExceptionWithMessageIfEmpty($bucket, $errMsg);
+ }
+
+ /**
+ * 校验object参数
+ *
+ * @param string $object
+ * @throws OssException
+ */
+ private function precheckObject($object)
+ {
+ OssUtil::throwOssExceptionWithMessageIfEmpty($object, "object name is empty");
+ }
+
+ /**
+ * 校验option restore
+ *
+ * @param string $restore
+ * @throws OssException
+ */
+ private function precheckStorage($storage)
+ {
+ if (is_string($storage)) {
+ switch ($storage) {
+ case self::OSS_STORAGE_ARCHIVE:
+ return;
+ case self::OSS_STORAGE_IA:
+ return;
+ case self::OSS_STORAGE_STANDARD:
+ return;
+ default:
+ break;
+ }
+ }
+ throw new OssException('storage name is invalid');
+ }
+
+ /**
+ * 校验bucket,options参数
+ *
+ * @param string $bucket
+ * @param string $object
+ * @param array $options
+ * @param bool $isCheckObject
+ */
+ private function precheckCommon($bucket, $object, &$options, $isCheckObject = true)
+ {
+ if ($isCheckObject) {
+ $this->precheckObject($object);
+ }
+ $this->precheckOptions($options);
+ $this->precheckBucket($bucket);
+ }
+
+ /**
+ * 参数校验
+ *
+ * @param array $options
+ * @param string $param
+ * @param string $funcName
+ * @throws OssException
+ */
+ private function precheckParam($options, $param, $funcName)
+ {
+ if (!isset($options[$param])) {
+ throw new OssException('The `' . $param . '` options is required in ' . $funcName . '().');
+ }
+ }
+
+ /**
+ * 检测md5
+ *
+ * @param array $options
+ * @return bool|null
+ */
+ private function isCheckMD5($options)
+ {
+ return $this->getValue($options, self::OSS_CHECK_MD5, false, true, true);
+ }
+
+ /**
+ * 获取value
+ *
+ * @param array $options
+ * @param string $key
+ * @param string $default
+ * @param bool $isCheckEmpty
+ * @param bool $isCheckBool
+ * @return bool|null
+ */
+ private function getValue($options, $key, $default = NULL, $isCheckEmpty = false, $isCheckBool = false)
+ {
+ $value = $default;
+ if (isset($options[$key])) {
+ if ($isCheckEmpty) {
+ if (!empty($options[$key])) {
+ $value = $options[$key];
+ }
+ } else {
+ $value = $options[$key];
+ }
+ unset($options[$key]);
+ }
+ if ($isCheckBool) {
+ if ($value !== true && $value !== false) {
+ $value = false;
+ }
+ }
+ return $value;
+ }
+
+ /**
+ * 获取mimetype类型
+ *
+ * @param string $object
+ * @return string
+ */
+ private function getMimeType($object, $file = null)
+ {
+ if (!is_null($file)) {
+ $type = MimeTypes::getMimetype($file);
+ if (!is_null($type)) {
+ return $type;
+ }
+ }
+
+ $type = MimeTypes::getMimetype($object);
+ if (!is_null($type)) {
+ return $type;
+ }
+
+ return self::DEFAULT_CONTENT_TYPE;
+ }
+
+ /**
+ * 验证并且执行请求,按照OSS Api协议,执行操作
+ *
+ * @param array $options
+ * @return ResponseCore
+ * @throws OssException
+ * @throws RequestCore_Exception
+ */
+ private function auth($options)
+ {
+ OssUtil::validateOptions($options);
+ //验证bucket,list_bucket时不需要验证
+ $this->authPrecheckBucket($options);
+ //验证object
+ $this->authPrecheckObject($options);
+ //Object名称的编码必须是utf8
+ $this->authPrecheckObjectEncoding($options);
+ //验证ACL
+ $this->authPrecheckAcl($options);
+ // 获得当次请求使用的协议头,是https还是http
+ $scheme = $this->useSSL ? 'https://' : 'http://';
+ // 获得当次请求使用的hostname,如果是公共域名或者专有域名,bucket拼在前面构成三级域名
+ $hostname = $this->generateHostname($options[self::OSS_BUCKET]);
+ $string_to_sign = '';
+ $headers = $this->generateHeaders($options, $hostname);
+ $signable_query_string_params = $this->generateSignableQueryStringParam($options);
+ $signable_query_string = OssUtil::toQueryString($signable_query_string_params);
+ $resource_uri = $this->generateResourceUri($options);
+ //生成请求URL
+ $conjunction = '?';
+ $non_signable_resource = '';
+ if (isset($options[self::OSS_SUB_RESOURCE])) {
+ $conjunction = '&';
+ }
+ if ($signable_query_string !== '') {
+ $signable_query_string = $conjunction . $signable_query_string;
+ $conjunction = '&';
+ }
+ $query_string = $this->generateQueryString($options);
+ if ($query_string !== '') {
+ $non_signable_resource .= $conjunction . $query_string;
+ $conjunction = '&';
+ }
+ $this->requestUrl = $scheme . $hostname . $resource_uri . $signable_query_string . $non_signable_resource;
+
+ //创建请求
+ $request = new RequestCore($this->requestUrl, $this->requestProxy);
+ $request->set_useragent($this->generateUserAgent());
+ // Streaming uploads
+ if (isset($options[self::OSS_FILE_UPLOAD])) {
+ if (is_resource($options[self::OSS_FILE_UPLOAD])) {
+ $length = null;
+
+ if (isset($options[self::OSS_CONTENT_LENGTH])) {
+ $length = $options[self::OSS_CONTENT_LENGTH];
+ } elseif (isset($options[self::OSS_SEEK_TO])) {
+ $stats = fstat($options[self::OSS_FILE_UPLOAD]);
+ if ($stats && $stats[self::OSS_SIZE] >= 0) {
+ $length = $stats[self::OSS_SIZE] - (integer)$options[self::OSS_SEEK_TO];
+ }
+ }
+ $request->set_read_stream($options[self::OSS_FILE_UPLOAD], $length);
+ } else {
+ $request->set_read_file($options[self::OSS_FILE_UPLOAD]);
+ $length = $request->read_stream_size;
+ if (isset($options[self::OSS_CONTENT_LENGTH])) {
+ $length = $options[self::OSS_CONTENT_LENGTH];
+ } elseif (isset($options[self::OSS_SEEK_TO]) && isset($length)) {
+ $length -= (integer)$options[self::OSS_SEEK_TO];
+ }
+ $request->set_read_stream_size($length);
+ }
+ }
+ if (isset($options[self::OSS_SEEK_TO])) {
+ $request->set_seek_position((integer)$options[self::OSS_SEEK_TO]);
+ }
+ if (isset($options[self::OSS_FILE_DOWNLOAD])) {
+ if (is_resource($options[self::OSS_FILE_DOWNLOAD])) {
+ $request->set_write_stream($options[self::OSS_FILE_DOWNLOAD]);
+ } else {
+ $request->set_write_file($options[self::OSS_FILE_DOWNLOAD]);
+ }
+ }
+
+ if (isset($options[self::OSS_METHOD])) {
+ $request->set_method($options[self::OSS_METHOD]);
+ $string_to_sign .= $options[self::OSS_METHOD] . "\n";
+ }
+
+ if (isset($options[self::OSS_CONTENT])) {
+ $request->set_body($options[self::OSS_CONTENT]);
+ if ($headers[self::OSS_CONTENT_TYPE] === 'application/x-www-form-urlencoded') {
+ $headers[self::OSS_CONTENT_TYPE] = 'application/octet-stream';
+ }
+
+ $headers[self::OSS_CONTENT_LENGTH] = strlen($options[self::OSS_CONTENT]);
+ $headers[self::OSS_CONTENT_MD5] = base64_encode(md5($options[self::OSS_CONTENT], true));
+ }
+
+ if (isset($options[self::OSS_CALLBACK])) {
+ $headers[self::OSS_CALLBACK] = base64_encode($options[self::OSS_CALLBACK]);
+ }
+ if (isset($options[self::OSS_CALLBACK_VAR])) {
+ $headers[self::OSS_CALLBACK_VAR] = base64_encode($options[self::OSS_CALLBACK_VAR]);
+ }
+
+ if (!isset($headers[self::OSS_ACCEPT_ENCODING])) {
+ $headers[self::OSS_ACCEPT_ENCODING] = '';
+ }
+
+ uksort($headers, 'strnatcasecmp');
+
+ foreach ($headers as $header_key => $header_value) {
+ $header_value = str_replace(array("\r", "\n"), '', $header_value);
+ if ($header_value !== '' || $header_key === self::OSS_ACCEPT_ENCODING) {
+ $request->add_header($header_key, $header_value);
+ }
+
+ if (
+ strtolower($header_key) === 'content-md5' ||
+ strtolower($header_key) === 'content-type' ||
+ strtolower($header_key) === 'date' ||
+ (isset($options['self::OSS_PREAUTH']) && (integer)$options['self::OSS_PREAUTH'] > 0)
+ ) {
+ $string_to_sign .= $header_value . "\n";
+ } elseif (substr(strtolower($header_key), 0, 6) === self::OSS_DEFAULT_PREFIX) {
+ $string_to_sign .= strtolower($header_key) . ':' . $header_value . "\n";
+ }
+ }
+ // 生成 signable_resource
+ $signable_resource = $this->generateSignableResource($options);
+ $string_to_sign .= rawurldecode($signable_resource) . urldecode($signable_query_string);
+
+ //对?后面的要签名的string字母序排序
+ $string_to_sign_ordered = $this->stringToSignSorted($string_to_sign);
+
+ $signature = base64_encode(hash_hmac('sha1', $string_to_sign_ordered, $this->accessKeySecret, true));
+ $request->add_header('Authorization', 'OSS ' . $this->accessKeyId . ':' . $signature);
+
+ if (isset($options[self::OSS_PREAUTH]) && (integer)$options[self::OSS_PREAUTH] > 0) {
+ $signed_url = $this->requestUrl . $conjunction . self::OSS_URL_ACCESS_KEY_ID . '=' . rawurlencode($this->accessKeyId) . '&' . self::OSS_URL_EXPIRES . '=' . $options[self::OSS_PREAUTH] . '&' . self::OSS_URL_SIGNATURE . '=' . rawurlencode($signature);
+ return $signed_url;
+ } elseif (isset($options[self::OSS_PREAUTH])) {
+ return $this->requestUrl;
+ }
+
+ if ($this->timeout !== 0) {
+ $request->timeout = $this->timeout;
+ }
+ if ($this->connectTimeout !== 0) {
+ $request->connect_timeout = $this->connectTimeout;
+ }
+
+ try {
+ $request->send_request();
+ } catch (RequestCore_Exception $e) {
+ throw(new OssException('RequestCoreException: ' . $e->getMessage()));
+ }
+ $response_header = $request->get_response_header();
+ $response_header['oss-request-url'] = $this->requestUrl;
+ $response_header['oss-redirects'] = $this->redirects;
+ $response_header['oss-stringtosign'] = $string_to_sign;
+ $response_header['oss-requestheaders'] = $request->request_headers;
+
+ $data = new ResponseCore($response_header, $request->get_response_body(), $request->get_response_code());
+ //retry if OSS Internal Error
+ if ((integer)$request->get_response_code() === 500) {
+ if ($this->redirects <= $this->maxRetries) {
+ //设置休眠
+ $delay = (integer)(pow(4, $this->redirects) * 100000);
+ usleep($delay);
+ $this->redirects++;
+ $data = $this->auth($options);
+ }
+ }
+
+ $this->redirects = 0;
+ return $data;
+ }
+
+ /**
+ * 设置最大尝试次数
+ *
+ * @param int $maxRetries
+ * @return void
+ */
+ public function setMaxTries($maxRetries = 3)
+ {
+ $this->maxRetries = $maxRetries;
+ }
+
+ /**
+ * 获取最大尝试次数
+ *
+ * @return int
+ */
+ public function getMaxRetries()
+ {
+ return $this->maxRetries;
+ }
+
+ /**
+ * 打开sts enable标志,使用户构造函数中传入的$sts生效
+ *
+ * @param boolean $enable
+ */
+ public function setSignStsInUrl($enable)
+ {
+ $this->enableStsInUrl = $enable;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function isUseSSL()
+ {
+ return $this->useSSL;
+ }
+
+ /**
+ * @param boolean $useSSL
+ */
+ public function setUseSSL($useSSL)
+ {
+ $this->useSSL = $useSSL;
+ }
+
+ /**
+ * 检查bucket名称格式是否正确,如果非法抛出异常
+ *
+ * @param $options
+ * @throws OssException
+ */
+ private function authPrecheckBucket($options)
+ {
+ if (!(('/' == $options[self::OSS_OBJECT]) && ('' == $options[self::OSS_BUCKET]) && ('GET' == $options[self::OSS_METHOD])) && !OssUtil::validateBucket($options[self::OSS_BUCKET])) {
+ throw new OssException('"' . $options[self::OSS_BUCKET] . '"' . 'bucket name is invalid');
+ }
+ }
+
+ /**
+ *
+ * 检查object名称格式是否正确,如果非法抛出异常
+ *
+ * @param $options
+ * @throws OssException
+ */
+ private function authPrecheckObject($options)
+ {
+ if (isset($options[self::OSS_OBJECT]) && $options[self::OSS_OBJECT] === '/') {
+ return;
+ }
+
+ if (isset($options[self::OSS_OBJECT]) && !OssUtil::validateObject($options[self::OSS_OBJECT])) {
+ throw new OssException('"' . $options[self::OSS_OBJECT] . '"' . ' object name is invalid');
+ }
+ }
+
+ /**
+ * 检查object的编码,如果是gbk或者gb2312则尝试将其转化为utf8编码
+ *
+ * @param mixed $options 参数
+ */
+ private function authPrecheckObjectEncoding(&$options)
+ {
+ $tmp_object = $options[self::OSS_OBJECT];
+ try {
+ if (OssUtil::isGb2312($options[self::OSS_OBJECT])) {
+ $options[self::OSS_OBJECT] = iconv('GB2312', "UTF-8//IGNORE", $options[self::OSS_OBJECT]);
+ } elseif (OssUtil::checkChar($options[self::OSS_OBJECT], true)) {
+ $options[self::OSS_OBJECT] = iconv('GBK', "UTF-8//IGNORE", $options[self::OSS_OBJECT]);
+ }
+ } catch (\Exception $e) {
+ try {
+ $tmp_object = iconv(mb_detect_encoding($tmp_object), "UTF-8", $tmp_object);
+ } catch (\Exception $e) {
+ }
+ }
+ $options[self::OSS_OBJECT] = $tmp_object;
+ }
+
+ /**
+ * 检查ACL是否是预定义中三种之一,如果不是抛出异常
+ *
+ * @param $options
+ * @throws OssException
+ */
+ private function authPrecheckAcl($options)
+ {
+ if (isset($options[self::OSS_HEADERS][self::OSS_ACL]) && !empty($options[self::OSS_HEADERS][self::OSS_ACL])) {
+ if (!in_array(strtolower($options[self::OSS_HEADERS][self::OSS_ACL]), self::$OSS_ACL_TYPES)) {
+ throw new OssException($options[self::OSS_HEADERS][self::OSS_ACL] . ':' . 'acl is invalid(private,public-read,public-read-write)');
+ }
+ }
+ }
+
+ /**
+ * 获得档次请求使用的域名
+ * bucket在前的三级域名,或者二级域名,如果是cname或者ip的话,则是二级域名
+ *
+ * @param $bucket
+ * @return string 剥掉协议头的域名
+ */
+ private function generateHostname($bucket)
+ {
+ if ($this->hostType === self::OSS_HOST_TYPE_IP) {
+ $hostname = $this->hostname;
+ } elseif ($this->hostType === self::OSS_HOST_TYPE_CNAME) {
+ $hostname = $this->hostname;
+ } else {
+ // 专有域或者官网endpoint
+ $hostname = ($bucket == '') ? $this->hostname : ($bucket . '.') . $this->hostname;
+ }
+ return $hostname;
+ }
+
+ /**
+ * 获得当次请求的资源定位字段
+ *
+ * @param $options
+ * @return string 资源定位字段
+ */
+ private function generateResourceUri($options)
+ {
+ $resource_uri = "";
+
+ // resource_uri + bucket
+ if (isset($options[self::OSS_BUCKET]) && '' !== $options[self::OSS_BUCKET]) {
+ if ($this->hostType === self::OSS_HOST_TYPE_IP) {
+ $resource_uri = '/' . $options[self::OSS_BUCKET];
+ }
+ }
+
+ // resource_uri + object
+ if (isset($options[self::OSS_OBJECT]) && '/' !== $options[self::OSS_OBJECT]) {
+ $resource_uri .= '/' . str_replace(array('%2F', '%25'), array('/', '%'), rawurlencode($options[self::OSS_OBJECT]));
+ }
+
+ // resource_uri + sub_resource
+ $conjunction = '?';
+ if (isset($options[self::OSS_SUB_RESOURCE])) {
+ $resource_uri .= $conjunction . $options[self::OSS_SUB_RESOURCE];
+ }
+ return $resource_uri;
+ }
+
+ /**
+ * 生成signalbe_query_string_param, array类型
+ *
+ * @param array $options
+ * @return array
+ */
+ private function generateSignableQueryStringParam($options)
+ {
+ $signableQueryStringParams = array();
+ $signableList = array(
+ self::OSS_PART_NUM,
+ 'response-content-type',
+ 'response-content-language',
+ 'response-cache-control',
+ 'response-content-encoding',
+ 'response-expires',
+ 'response-content-disposition',
+ self::OSS_UPLOAD_ID,
+ self::OSS_COMP,
+ self::OSS_LIVE_CHANNEL_STATUS,
+ self::OSS_LIVE_CHANNEL_START_TIME,
+ self::OSS_LIVE_CHANNEL_END_TIME,
+ self::OSS_PROCESS,
+ self::OSS_POSITION,
+ self::OSS_SYMLINK,
+ self::OSS_RESTORE,
+ );
+
+ foreach ($signableList as $item) {
+ if (isset($options[$item])) {
+ $signableQueryStringParams[$item] = $options[$item];
+ }
+ }
+
+ if ($this->enableStsInUrl && (!is_null($this->securityToken))) {
+ $signableQueryStringParams["security-token"] = $this->securityToken;
+ }
+
+ return $signableQueryStringParams;
+ }
+
+ /**
+ * 生成用于签名resource段
+ *
+ * @param mixed $options
+ * @return string
+ */
+ private function generateSignableResource($options)
+ {
+ $signableResource = "";
+ $signableResource .= '/';
+ if (isset($options[self::OSS_BUCKET]) && '' !== $options[self::OSS_BUCKET]) {
+ $signableResource .= $options[self::OSS_BUCKET];
+ // 如果操作没有Object操作的话,这里最后是否有斜线有个trick,ip的域名下,不需要加'/', 否则需要加'/'
+ if ($options[self::OSS_OBJECT] == '/') {
+ if ($this->hostType !== self::OSS_HOST_TYPE_IP) {
+ $signableResource .= "/";
+ }
+ }
+ }
+ //signable_resource + object
+ if (isset($options[self::OSS_OBJECT]) && '/' !== $options[self::OSS_OBJECT]) {
+ $signableResource .= '/' . str_replace(array('%2F', '%25'), array('/', '%'), rawurlencode($options[self::OSS_OBJECT]));
+ }
+ if (isset($options[self::OSS_SUB_RESOURCE])) {
+ $signableResource .= '?' . $options[self::OSS_SUB_RESOURCE];
+ }
+ return $signableResource;
+ }
+
+ /**
+ * 生成query_string
+ *
+ * @param mixed $options
+ * @return string
+ */
+ private function generateQueryString($options)
+ {
+ //请求参数
+ $queryStringParams = array();
+ if (isset($options[self::OSS_QUERY_STRING])) {
+ $queryStringParams = array_merge($queryStringParams, $options[self::OSS_QUERY_STRING]);
+ }
+ return OssUtil::toQueryString($queryStringParams);
+ }
+
+ private function stringToSignSorted($string_to_sign)
+ {
+ $queryStringSorted = '';
+ $explodeResult = explode('?', $string_to_sign);
+ $index = count($explodeResult);
+ if ($index === 1)
+ return $string_to_sign;
+
+ $queryStringParams = explode('&', $explodeResult[$index - 1]);
+ sort($queryStringParams);
+
+ foreach ($queryStringParams as $params) {
+ $queryStringSorted .= $params . '&';
+ }
+
+ $queryStringSorted = substr($queryStringSorted, 0, -1);
+
+ return $explodeResult[0] . '?' . $queryStringSorted;
+ }
+
+ /**
+ * 初始化headers
+ *
+ * @param mixed $options
+ * @param string $hostname hostname
+ * @return array
+ */
+ private function generateHeaders($options, $hostname)
+ {
+ $headers = array(
+ self::OSS_CONTENT_MD5 => '',
+ self::OSS_CONTENT_TYPE => isset($options[self::OSS_CONTENT_TYPE]) ? $options[self::OSS_CONTENT_TYPE] : self::DEFAULT_CONTENT_TYPE,
+ self::OSS_DATE => isset($options[self::OSS_DATE]) ? $options[self::OSS_DATE] : gmdate('D, d M Y H:i:s \G\M\T'),
+ self::OSS_HOST => $hostname,
+ );
+ if (isset($options[self::OSS_CONTENT_MD5])) {
+ $headers[self::OSS_CONTENT_MD5] = $options[self::OSS_CONTENT_MD5];
+ }
+
+ //添加stsSecurityToken
+ if ((!is_null($this->securityToken)) && (!$this->enableStsInUrl)) {
+ $headers[self::OSS_SECURITY_TOKEN] = $this->securityToken;
+ }
+ //合并HTTP headers
+ if (isset($options[self::OSS_HEADERS])) {
+ $headers = array_merge($headers, $options[self::OSS_HEADERS]);
+ }
+ return $headers;
+ }
+
+ /**
+ * 生成请求用的UserAgent
+ *
+ * @return string
+ */
+ private function generateUserAgent()
+ {
+ return self::OSS_NAME . "/" . self::OSS_VERSION . " (" . php_uname('s') . "/" . php_uname('r') . "/" . php_uname('m') . ";" . PHP_VERSION . ")";
+ }
+
+ /**
+ * 检查endpoint的种类
+ * 如有有协议头,剥去协议头
+ * 并且根据参数 is_cname 和endpoint本身,判定域名类型,是ip,cname,还是专有域或者官网域名
+ *
+ * @param string $endpoint
+ * @param boolean $isCName
+ * @return string 剥掉协议头的域名
+ */
+ private function checkEndpoint($endpoint, $isCName)
+ {
+ $ret_endpoint = null;
+ if (strpos($endpoint, 'http://') === 0) {
+ $ret_endpoint = substr($endpoint, strlen('http://'));
+ } elseif (strpos($endpoint, 'https://') === 0) {
+ $ret_endpoint = substr($endpoint, strlen('https://'));
+ $this->useSSL = true;
+ } else {
+ $ret_endpoint = $endpoint;
+ }
+
+ if ($isCName) {
+ $this->hostType = self::OSS_HOST_TYPE_CNAME;
+ } elseif (OssUtil::isIPFormat($ret_endpoint)) {
+ $this->hostType = self::OSS_HOST_TYPE_IP;
+ } else {
+ $this->hostType = self::OSS_HOST_TYPE_NORMAL;
+ }
+ return $ret_endpoint;
+ }
+
+ /**
+ * 用来检查sdk所以来的扩展是否打开
+ *
+ * @throws OssException
+ */
+ public static function checkEnv()
+ {
+ if (function_exists('get_loaded_extensions')) {
+ //检测curl扩展
+ $enabled_extension = array("curl");
+ $extensions = get_loaded_extensions();
+ if ($extensions) {
+ foreach ($enabled_extension as $item) {
+ if (!in_array($item, $extensions)) {
+ throw new OssException("Extension {" . $item . "} is not installed or not enabled, please check your php env.");
+ }
+ }
+ } else {
+ throw new OssException("function get_loaded_extensions not found.");
+ }
+ } else {
+ throw new OssException('Function get_loaded_extensions has been disabled, please check php config.');
+ }
+ }
+
+ /**
+ * //* 设置http库的请求超时时间,单位秒
+ *
+ * @param int $timeout
+ */
+ public function setTimeout($timeout)
+ {
+ $this->timeout = $timeout;
+ }
+
+ /**
+ * 设置http库的连接超时时间,单位秒
+ *
+ * @param int $connectTimeout
+ */
+ public function setConnectTimeout($connectTimeout)
+ {
+ $this->connectTimeout = $connectTimeout;
+ }
+
+ // 生命周期相关常量
+ const OSS_LIFECYCLE_EXPIRATION = "Expiration";
+ const OSS_LIFECYCLE_TIMING_DAYS = "Days";
+ const OSS_LIFECYCLE_TIMING_DATE = "Date";
+ //OSS 内部常量
+ const OSS_BUCKET = 'bucket';
+ const OSS_OBJECT = 'object';
+ const OSS_HEADERS = OssUtil::OSS_HEADERS;
+ const OSS_METHOD = 'method';
+ const OSS_QUERY = 'query';
+ const OSS_BASENAME = 'basename';
+ const OSS_MAX_KEYS = 'max-keys';
+ const OSS_UPLOAD_ID = 'uploadId';
+ const OSS_PART_NUM = 'partNumber';
+ const OSS_COMP = 'comp';
+ const OSS_LIVE_CHANNEL_STATUS = 'status';
+ const OSS_LIVE_CHANNEL_START_TIME = 'startTime';
+ const OSS_LIVE_CHANNEL_END_TIME = 'endTime';
+ const OSS_POSITION = 'position';
+ const OSS_MAX_KEYS_VALUE = 100;
+ const OSS_MAX_OBJECT_GROUP_VALUE = OssUtil::OSS_MAX_OBJECT_GROUP_VALUE;
+ const OSS_MAX_PART_SIZE = OssUtil::OSS_MAX_PART_SIZE;
+ const OSS_MID_PART_SIZE = OssUtil::OSS_MID_PART_SIZE;
+ const OSS_MIN_PART_SIZE = OssUtil::OSS_MIN_PART_SIZE;
+ const OSS_FILE_SLICE_SIZE = 8192;
+ const OSS_PREFIX = 'prefix';
+ const OSS_DELIMITER = 'delimiter';
+ const OSS_MARKER = 'marker';
+ const OSS_ACCEPT_ENCODING = 'Accept-Encoding';
+ const OSS_CONTENT_MD5 = 'Content-Md5';
+ const OSS_SELF_CONTENT_MD5 = 'x-oss-meta-md5';
+ const OSS_CONTENT_TYPE = 'Content-Type';
+ const OSS_CONTENT_LENGTH = 'Content-Length';
+ const OSS_IF_MODIFIED_SINCE = 'If-Modified-Since';
+ const OSS_IF_UNMODIFIED_SINCE = 'If-Unmodified-Since';
+ const OSS_IF_MATCH = 'If-Match';
+ const OSS_IF_NONE_MATCH = 'If-None-Match';
+ const OSS_CACHE_CONTROL = 'Cache-Control';
+ const OSS_EXPIRES = 'Expires';
+ const OSS_PREAUTH = 'preauth';
+ const OSS_CONTENT_COING = 'Content-Coding';
+ const OSS_CONTENT_DISPOSTION = 'Content-Disposition';
+ const OSS_RANGE = 'range';
+ const OSS_ETAG = 'etag';
+ const OSS_LAST_MODIFIED = 'lastmodified';
+ const OS_CONTENT_RANGE = 'Content-Range';
+ const OSS_CONTENT = OssUtil::OSS_CONTENT;
+ const OSS_BODY = 'body';
+ const OSS_LENGTH = OssUtil::OSS_LENGTH;
+ const OSS_HOST = 'Host';
+ const OSS_DATE = 'Date';
+ const OSS_AUTHORIZATION = 'Authorization';
+ const OSS_FILE_DOWNLOAD = 'fileDownload';
+ const OSS_FILE_UPLOAD = 'fileUpload';
+ const OSS_PART_SIZE = 'partSize';
+ const OSS_SEEK_TO = 'seekTo';
+ const OSS_SIZE = 'size';
+ const OSS_QUERY_STRING = 'query_string';
+ const OSS_SUB_RESOURCE = 'sub_resource';
+ const OSS_DEFAULT_PREFIX = 'x-oss-';
+ const OSS_CHECK_MD5 = 'checkmd5';
+ const DEFAULT_CONTENT_TYPE = 'application/octet-stream';
+ const OSS_SYMLINK_TARGET = 'x-oss-symlink-target';
+ const OSS_SYMLINK = 'symlink';
+ const OSS_HTTP_CODE = 'http_code';
+ const OSS_REQUEST_ID = 'x-oss-request-id';
+ const OSS_INFO = 'info';
+ const OSS_STORAGE = 'storage';
+ const OSS_RESTORE = 'restore';
+ const OSS_STORAGE_STANDARD = 'Standard';
+ const OSS_STORAGE_IA = 'IA';
+ const OSS_STORAGE_ARCHIVE = 'Archive';
+
+ //私有URL变量
+ const OSS_URL_ACCESS_KEY_ID = 'OSSAccessKeyId';
+ const OSS_URL_EXPIRES = 'Expires';
+ const OSS_URL_SIGNATURE = 'Signature';
+ //HTTP方法
+ const OSS_HTTP_GET = 'GET';
+ const OSS_HTTP_PUT = 'PUT';
+ const OSS_HTTP_HEAD = 'HEAD';
+ const OSS_HTTP_POST = 'POST';
+ const OSS_HTTP_DELETE = 'DELETE';
+ const OSS_HTTP_OPTIONS = 'OPTIONS';
+ //其他常量
+ const OSS_ACL = 'x-oss-acl';
+ const OSS_OBJECT_ACL = 'x-oss-object-acl';
+ const OSS_OBJECT_GROUP = 'x-oss-file-group';
+ const OSS_MULTI_PART = 'uploads';
+ const OSS_MULTI_DELETE = 'delete';
+ const OSS_OBJECT_COPY_SOURCE = 'x-oss-copy-source';
+ const OSS_OBJECT_COPY_SOURCE_RANGE = "x-oss-copy-source-range";
+ const OSS_PROCESS = "x-oss-process";
+ const OSS_CALLBACK = "x-oss-callback";
+ const OSS_CALLBACK_VAR = "x-oss-callback-var";
+ //支持STS SecurityToken
+ const OSS_SECURITY_TOKEN = "x-oss-security-token";
+ const OSS_ACL_TYPE_PRIVATE = 'private';
+ const OSS_ACL_TYPE_PUBLIC_READ = 'public-read';
+ const OSS_ACL_TYPE_PUBLIC_READ_WRITE = 'public-read-write';
+ const OSS_ENCODING_TYPE = "encoding-type";
+ const OSS_ENCODING_TYPE_URL = "url";
+
+ // 域名类型
+ const OSS_HOST_TYPE_NORMAL = "normal";//http://bucket.oss-cn-hangzhou.aliyuncs.com/object
+ const OSS_HOST_TYPE_IP = "ip"; //http://1.1.1.1/bucket/object
+ const OSS_HOST_TYPE_SPECIAL = 'special'; //http://bucket.guizhou.gov/object
+ const OSS_HOST_TYPE_CNAME = "cname"; //http://mydomain.com/object
+ //OSS ACL数组
+ static $OSS_ACL_TYPES = array(
+ self::OSS_ACL_TYPE_PRIVATE,
+ self::OSS_ACL_TYPE_PUBLIC_READ,
+ self::OSS_ACL_TYPE_PUBLIC_READ_WRITE
+ );
+ // OssClient版本信息
+ const OSS_NAME = "aliyun-sdk-php";
+ const OSS_VERSION = "2.3.0";
+ const OSS_BUILD = "20180105";
+ const OSS_AUTHOR = "";
+ const OSS_OPTIONS_ORIGIN = 'Origin';
+ const OSS_OPTIONS_REQUEST_METHOD = 'Access-Control-Request-Method';
+ const OSS_OPTIONS_REQUEST_HEADERS = 'Access-Control-Request-Headers';
+
+ //是否使用ssl
+ private $useSSL = false;
+ private $maxRetries = 3;
+ private $redirects = 0;
+
+ // 用户提供的域名类型,有四种 OSS_HOST_TYPE_NORMAL, OSS_HOST_TYPE_IP, OSS_HOST_TYPE_SPECIAL, OSS_HOST_TYPE_CNAME
+ private $hostType = self::OSS_HOST_TYPE_NORMAL;
+ private $requestUrl;
+ private $accessKeyId;
+ private $accessKeySecret;
+ private $hostname;
+ private $securityToken;
+ private $requestProxy = null;
+ private $enableStsInUrl = false;
+ private $timeout = 0;
+ private $connectTimeout = 0;
+}
diff --git a/addons/alioss/library/OSS/Result/AclResult.php b/addons/alioss/library/OSS/Result/AclResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..6da0860420ff90be9707490fc6f53370077781f2
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/AclResult.php
@@ -0,0 +1,32 @@
+rawResponse->body;
+ if (empty($content)) {
+ throw new OssException("body is null");
+ }
+ $xml = simplexml_load_string($content);
+ if (isset($xml->AccessControlList->Grant)) {
+ return strval($xml->AccessControlList->Grant);
+ } else {
+ throw new OssException("xml format exception");
+ }
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/AppendResult.php b/addons/alioss/library/OSS/Result/AppendResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..433c03eb13cfae73113d332beb6e23e8c367e4b8
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/AppendResult.php
@@ -0,0 +1,27 @@
+rawResponse->header;
+ if (isset($header["x-oss-next-append-position"])) {
+ return intval($header["x-oss-next-append-position"]);
+ }
+ throw new OssException("cannot get next-append-position");
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/BodyResult.php b/addons/alioss/library/OSS/Result/BodyResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..44ba15ef5864bbed254158fb440e24ee8345670c
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/BodyResult.php
@@ -0,0 +1,19 @@
+rawResponse->body) ? "" : $this->rawResponse->body;
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/CallbackResult.php b/addons/alioss/library/OSS/Result/CallbackResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..514e985c244d47b0c3993b8280e103a49c0f3527
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/CallbackResult.php
@@ -0,0 +1,21 @@
+rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 && (int)(intval($status)) !== 203) {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/addons/alioss/library/OSS/Result/CopyObjectResult.php b/addons/alioss/library/OSS/Result/CopyObjectResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..498723e1b0b8045018c4b83df25ae8d1d19e0d75
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/CopyObjectResult.php
@@ -0,0 +1,30 @@
+rawResponse->body;
+ $xml = simplexml_load_string($body);
+ $result = array();
+
+ if (isset($xml->LastModified)) {
+ $result[] = $xml->LastModified;
+ }
+ if (isset($xml->ETag)) {
+ $result[] = $xml->ETag;
+ }
+
+ return $result;
+ }
+}
diff --git a/addons/alioss/library/OSS/Result/DeleteObjectsResult.php b/addons/alioss/library/OSS/Result/DeleteObjectsResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..dc373b85459b9fb6e5041cf37ab14f7d5df48c1e
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/DeleteObjectsResult.php
@@ -0,0 +1,27 @@
+rawResponse->body;
+ $xml = simplexml_load_string($body);
+ $objects = array();
+
+ if (isset($xml->Deleted)) {
+ foreach($xml->Deleted as $deleteKey)
+ $objects[] = $deleteKey->Key;
+ }
+ return $objects;
+ }
+}
diff --git a/addons/alioss/library/OSS/Result/ExistResult.php b/addons/alioss/library/OSS/Result/ExistResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..f7aa287c8d566aba591a11ab8328c9938dd6293d
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/ExistResult.php
@@ -0,0 +1,35 @@
+rawResponse->status) === 200 ? true : false;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 判断是否存在的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/GetCnameResult.php b/addons/alioss/library/OSS/Result/GetCnameResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..eed01f9021cb7acadbd77a249c82e8ff9e3e8db9
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetCnameResult.php
@@ -0,0 +1,19 @@
+rawResponse->body;
+ $config = new CnameConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/GetCorsResult.php b/addons/alioss/library/OSS/Result/GetCorsResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..a51afe2a80787220943acab953147a7381e232ca
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetCorsResult.php
@@ -0,0 +1,35 @@
+rawResponse->body;
+ $config = new CorsConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/GetLifecycleResult.php b/addons/alioss/library/OSS/Result/GetLifecycleResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..6b440c35217829ef537230ed3fc6c8c38c7fab6e
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetLifecycleResult.php
@@ -0,0 +1,41 @@
+rawResponse->body;
+ $config = new LifecycleConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/GetLiveChannelHistoryResult.php b/addons/alioss/library/OSS/Result/GetLiveChannelHistoryResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..202a6681df7829ffe5ddc482c60b7f47e4432e65
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetLiveChannelHistoryResult.php
@@ -0,0 +1,19 @@
+rawResponse->body;
+ $channelList = new GetLiveChannelHistory();
+ $channelList->parseFromXml($content);
+ return $channelList;
+ }
+}
diff --git a/addons/alioss/library/OSS/Result/GetLiveChannelInfoResult.php b/addons/alioss/library/OSS/Result/GetLiveChannelInfoResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..d5a9005e756073db2e1db7bf02db84f7b5579129
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetLiveChannelInfoResult.php
@@ -0,0 +1,19 @@
+rawResponse->body;
+ $channelList = new GetLiveChannelInfo();
+ $channelList->parseFromXml($content);
+ return $channelList;
+ }
+}
diff --git a/addons/alioss/library/OSS/Result/GetLiveChannelStatusResult.php b/addons/alioss/library/OSS/Result/GetLiveChannelStatusResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..6b8a60f5946af98b5b92b369948d35996095ae96
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetLiveChannelStatusResult.php
@@ -0,0 +1,19 @@
+rawResponse->body;
+ $channelList = new GetLiveChannelStatus();
+ $channelList->parseFromXml($content);
+ return $channelList;
+ }
+}
diff --git a/addons/alioss/library/OSS/Result/GetLocationResult.php b/addons/alioss/library/OSS/Result/GetLocationResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..71c4c96e9629489435ebe69328d67623e62663fa
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetLocationResult.php
@@ -0,0 +1,30 @@
+rawResponse->body;
+ if (empty($content)) {
+ throw new OssException("body is null");
+ }
+ $xml = simplexml_load_string($content);
+ return $xml;
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/GetLoggingResult.php b/addons/alioss/library/OSS/Result/GetLoggingResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..72fc3aeb19931a7c99065a079fe0418284ed1726
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetLoggingResult.php
@@ -0,0 +1,41 @@
+rawResponse->body;
+ $config = new LoggingConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/GetRefererResult.php b/addons/alioss/library/OSS/Result/GetRefererResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..aee50d3aec447928c3e4aabdda5c6b1c8fb65ec6
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetRefererResult.php
@@ -0,0 +1,41 @@
+rawResponse->body;
+ $config = new RefererConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/GetStorageCapacityResult.php b/addons/alioss/library/OSS/Result/GetStorageCapacityResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..84e4916067a262cbdd6ef2e04eae9f388a30fb1e
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetStorageCapacityResult.php
@@ -0,0 +1,34 @@
+rawResponse->body;
+ if (empty($content)) {
+ throw new OssException("body is null");
+ }
+ $xml = simplexml_load_string($content);
+ if (isset($xml->StorageCapacity)) {
+ return intval($xml->StorageCapacity);
+ } else {
+ throw new OssException("xml format exception");
+ }
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/GetWebsiteResult.php b/addons/alioss/library/OSS/Result/GetWebsiteResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..3099172cd6fdeeb7c14af1c102cf95026bf0073c
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/GetWebsiteResult.php
@@ -0,0 +1,40 @@
+rawResponse->body;
+ $config = new WebsiteConfig();
+ $config->parseFromXml($content);
+ return $config;
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK, 获取bucket相关配置的接口,404也认为是一种
+ * 有效响应
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2 || (int)(intval($status)) === 404) {
+ return true;
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/HeaderResult.php b/addons/alioss/library/OSS/Result/HeaderResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..c9aae561ffd2608ce44135994e0b2046c94c9388
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/HeaderResult.php
@@ -0,0 +1,23 @@
+rawResponse->header) ? array() : $this->rawResponse->header;
+ }
+
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/InitiateMultipartUploadResult.php b/addons/alioss/library/OSS/Result/InitiateMultipartUploadResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..af985f272418e85a5fb148a1a7e7df23745de9dc
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/InitiateMultipartUploadResult.php
@@ -0,0 +1,29 @@
+rawResponse->body;
+ $xml = simplexml_load_string($content);
+ if (isset($xml->UploadId)) {
+ return strval($xml->UploadId);
+ }
+ throw new OssException("cannot get UploadId");
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/ListBucketsResult.php b/addons/alioss/library/OSS/Result/ListBucketsResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..a58fb2d612a25cc227e7abf0d8c76587cf4afa73
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/ListBucketsResult.php
@@ -0,0 +1,33 @@
+rawResponse->body;
+ $xml = new \SimpleXMLElement($content);
+ if (isset($xml->Buckets) && isset($xml->Buckets->Bucket)) {
+ foreach ($xml->Buckets->Bucket as $bucket) {
+ $bucketInfo = new BucketInfo(strval($bucket->Location),
+ strval($bucket->Name),
+ strval($bucket->CreationDate));
+ $bucketList[] = $bucketInfo;
+ }
+ }
+ return new BucketListInfo($bucketList);
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/ListLiveChannelResult.php b/addons/alioss/library/OSS/Result/ListLiveChannelResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..1a6e2a41fe96377000669f0c84bb66c490d3e44b
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/ListLiveChannelResult.php
@@ -0,0 +1,16 @@
+rawResponse->body;
+ $channelList = new LiveChannelListInfo();
+ $channelList->parseFromXml($content);
+ return $channelList;
+ }
+}
diff --git a/addons/alioss/library/OSS/Result/ListMultipartUploadResult.php b/addons/alioss/library/OSS/Result/ListMultipartUploadResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..bcb20bf5945cdb83f6c97579e8c5a218c5dcffe9
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/ListMultipartUploadResult.php
@@ -0,0 +1,55 @@
+rawResponse->body;
+ $xml = simplexml_load_string($content);
+
+ $encodingType = isset($xml->EncodingType) ? strval($xml->EncodingType) : "";
+ $bucket = isset($xml->Bucket) ? strval($xml->Bucket) : "";
+ $keyMarker = isset($xml->KeyMarker) ? strval($xml->KeyMarker) : "";
+ $keyMarker = OssUtil::decodeKey($keyMarker, $encodingType);
+ $uploadIdMarker = isset($xml->UploadIdMarker) ? strval($xml->UploadIdMarker) : "";
+ $nextKeyMarker = isset($xml->NextKeyMarker) ? strval($xml->NextKeyMarker) : "";
+ $nextKeyMarker = OssUtil::decodeKey($nextKeyMarker, $encodingType);
+ $nextUploadIdMarker = isset($xml->NextUploadIdMarker) ? strval($xml->NextUploadIdMarker) : "";
+ $delimiter = isset($xml->Delimiter) ? strval($xml->Delimiter) : "";
+ $delimiter = OssUtil::decodeKey($delimiter, $encodingType);
+ $prefix = isset($xml->Prefix) ? strval($xml->Prefix) : "";
+ $prefix = OssUtil::decodeKey($prefix, $encodingType);
+ $maxUploads = isset($xml->MaxUploads) ? intval($xml->MaxUploads) : 0;
+ $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : "";
+ $listUpload = array();
+
+ if (isset($xml->Upload)) {
+ foreach ($xml->Upload as $upload) {
+ $key = isset($upload->Key) ? strval($upload->Key) : "";
+ $key = OssUtil::decodeKey($key, $encodingType);
+ $uploadId = isset($upload->UploadId) ? strval($upload->UploadId) : "";
+ $initiated = isset($upload->Initiated) ? strval($upload->Initiated) : "";
+ $listUpload[] = new UploadInfo($key, $uploadId, $initiated);
+ }
+ }
+ return new ListMultipartUploadInfo($bucket, $keyMarker, $uploadIdMarker,
+ $nextKeyMarker, $nextUploadIdMarker,
+ $delimiter, $prefix, $maxUploads, $isTruncated, $listUpload);
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/ListObjectsResult.php b/addons/alioss/library/OSS/Result/ListObjectsResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..fcf493d25d166d9e58d12add25fa907af9931cd6
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/ListObjectsResult.php
@@ -0,0 +1,71 @@
+rawResponse->body);
+ $encodingType = isset($xml->EncodingType) ? strval($xml->EncodingType) : "";
+ $objectList = $this->parseObjectList($xml, $encodingType);
+ $prefixList = $this->parsePrefixList($xml, $encodingType);
+ $bucketName = isset($xml->Name) ? strval($xml->Name) : "";
+ $prefix = isset($xml->Prefix) ? strval($xml->Prefix) : "";
+ $prefix = OssUtil::decodeKey($prefix, $encodingType);
+ $marker = isset($xml->Marker) ? strval($xml->Marker) : "";
+ $marker = OssUtil::decodeKey($marker, $encodingType);
+ $maxKeys = isset($xml->MaxKeys) ? intval($xml->MaxKeys) : 0;
+ $delimiter = isset($xml->Delimiter) ? strval($xml->Delimiter) : "";
+ $delimiter = OssUtil::decodeKey($delimiter, $encodingType);
+ $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : "";
+ $nextMarker = isset($xml->NextMarker) ? strval($xml->NextMarker) : "";
+ $nextMarker = OssUtil::decodeKey($nextMarker, $encodingType);
+ return new ObjectListInfo($bucketName, $prefix, $marker, $nextMarker, $maxKeys, $delimiter, $isTruncated, $objectList, $prefixList);
+ }
+
+ private function parseObjectList($xml, $encodingType)
+ {
+ $retList = array();
+ if (isset($xml->Contents)) {
+ foreach ($xml->Contents as $content) {
+ $key = isset($content->Key) ? strval($content->Key) : "";
+ $key = OssUtil::decodeKey($key, $encodingType);
+ $lastModified = isset($content->LastModified) ? strval($content->LastModified) : "";
+ $eTag = isset($content->ETag) ? strval($content->ETag) : "";
+ $type = isset($content->Type) ? strval($content->Type) : "";
+ $size = isset($content->Size) ? intval($content->Size) : 0;
+ $storageClass = isset($content->StorageClass) ? strval($content->StorageClass) : "";
+ $retList[] = new ObjectInfo($key, $lastModified, $eTag, $type, $size, $storageClass);
+ }
+ }
+ return $retList;
+ }
+
+ private function parsePrefixList($xml, $encodingType)
+ {
+ $retList = array();
+ if (isset($xml->CommonPrefixes)) {
+ foreach ($xml->CommonPrefixes as $commonPrefix) {
+ $prefix = isset($commonPrefix->Prefix) ? strval($commonPrefix->Prefix) : "";
+ $prefix = OssUtil::decodeKey($prefix, $encodingType);
+ $retList[] = new PrefixInfo($prefix);
+ }
+ }
+ return $retList;
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/ListPartsResult.php b/addons/alioss/library/OSS/Result/ListPartsResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..fd8a1b863f063ae570990b9fc409769226d19ea7
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/ListPartsResult.php
@@ -0,0 +1,42 @@
+rawResponse->body;
+ $xml = simplexml_load_string($content);
+ $bucket = isset($xml->Bucket) ? strval($xml->Bucket) : "";
+ $key = isset($xml->Key) ? strval($xml->Key) : "";
+ $uploadId = isset($xml->UploadId) ? strval($xml->UploadId) : "";
+ $nextPartNumberMarker = isset($xml->NextPartNumberMarker) ? intval($xml->NextPartNumberMarker) : "";
+ $maxParts = isset($xml->MaxParts) ? intval($xml->MaxParts) : "";
+ $isTruncated = isset($xml->IsTruncated) ? strval($xml->IsTruncated) : "";
+ $partList = array();
+ if (isset($xml->Part)) {
+ foreach ($xml->Part as $part) {
+ $partNumber = isset($part->PartNumber) ? intval($part->PartNumber) : "";
+ $lastModified = isset($part->LastModified) ? strval($part->LastModified) : "";
+ $eTag = isset($part->ETag) ? strval($part->ETag) : "";
+ $size = isset($part->Size) ? intval($part->Size) : "";
+ $partList[] = new PartInfo($partNumber, $lastModified, $eTag, $size);
+ }
+ }
+ return new ListPartsInfo($bucket, $key, $uploadId, $nextPartNumberMarker, $maxParts, $isTruncated, $partList);
+ }
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/PutLiveChannelResult.php b/addons/alioss/library/OSS/Result/PutLiveChannelResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..dcac86b78ea3c026a19cbf44f0d66e9513861227
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/PutLiveChannelResult.php
@@ -0,0 +1,16 @@
+rawResponse->body;
+ $channel = new LiveChannelInfo();
+ $channel->parseFromXml($content);
+ return $channel;
+ }
+}
diff --git a/addons/alioss/library/OSS/Result/PutSetDeleteResult.php b/addons/alioss/library/OSS/Result/PutSetDeleteResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..97af003b6c05fece815cae0eb0f2357523a0c435
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/PutSetDeleteResult.php
@@ -0,0 +1,20 @@
+ $this->rawResponse->body);
+ return array_merge($this->rawResponse->header, $body);
+ }
+}
diff --git a/addons/alioss/library/OSS/Result/Result.php b/addons/alioss/library/OSS/Result/Result.php
new file mode 100644
index 0000000000000000000000000000000000000000..491256f00a46b3167eb699c7e4428ac643146544
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/Result.php
@@ -0,0 +1,175 @@
+rawResponse = $response;
+ $this->parseResponse();
+ }
+
+ /**
+ * 获取requestId
+ *
+ * @return string
+ */
+ public function getRequestId()
+ {
+ if (isset($this->rawResponse) &&
+ isset($this->rawResponse->header) &&
+ isset($this->rawResponse->header['x-oss-request-id'])
+ ) {
+ return $this->rawResponse->header['x-oss-request-id'];
+ } else {
+ return '';
+ }
+ }
+
+ /**
+ * 得到返回数据,不同的请求返回数据格式不同
+ *
+ * $return mixed
+ */
+ public function getData()
+ {
+ return $this->parsedData;
+ }
+
+ /**
+ * 由子类实现,不同的请求返回数据有不同的解析逻辑,由子类实现
+ *
+ * @return mixed
+ */
+ abstract protected function parseDataFromResponse();
+
+ /**
+ * 操作是否成功
+ *
+ * @return mixed
+ */
+ public function isOK()
+ {
+ return $this->isOk;
+ }
+
+ /**
+ * @throws OssException
+ */
+ public function parseResponse()
+ {
+ $this->isOk = $this->isResponseOk();
+ if ($this->isOk) {
+ $this->parsedData = $this->parseDataFromResponse();
+ } else {
+ $httpStatus = strval($this->rawResponse->status);
+ $requestId = strval($this->getRequestId());
+ $code = $this->retrieveErrorCode($this->rawResponse->body);
+ $message = $this->retrieveErrorMessage($this->rawResponse->body);
+ $body = $this->rawResponse->body;
+
+ $details = array(
+ 'status' => $httpStatus,
+ 'request-id' => $requestId,
+ 'code' => $code,
+ 'message' => $message,
+ 'body' => $body
+ );
+ throw new OssException($details);
+ }
+ }
+
+ /**
+ * 尝试从body中获取错误Message
+ *
+ * @param $body
+ * @return string
+ */
+ private function retrieveErrorMessage($body)
+ {
+ if (empty($body) || false === strpos($body, 'Message)) {
+ return strval($xml->Message);
+ }
+ return '';
+ }
+
+ /**
+ * 尝试从body中获取错误Code
+ *
+ * @param $body
+ * @return string
+ */
+ private function retrieveErrorCode($body)
+ {
+ if (empty($body) || false === strpos($body, 'Code)) {
+ return strval($xml->Code);
+ }
+ return '';
+ }
+
+ /**
+ * 根据返回http状态码判断,[200-299]即认为是OK
+ *
+ * @return bool
+ */
+ protected function isResponseOk()
+ {
+ $status = $this->rawResponse->status;
+ if ((int)(intval($status) / 100) == 2) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * 返回原始的返回数据
+ *
+ * @return ResponseCore
+ */
+ public function getRawResponse()
+ {
+ return $this->rawResponse;
+ }
+
+ /**
+ * 标示请求是否成功
+ */
+ protected $isOk = false;
+ /**
+ * 由子类解析过的数据
+ */
+ protected $parsedData = null;
+ /**
+ * 存放auth函数返回的原始Response
+ *
+ * @var ResponseCore
+ */
+ protected $rawResponse;
+}
\ No newline at end of file
diff --git a/addons/alioss/library/OSS/Result/SymlinkResult.php b/addons/alioss/library/OSS/Result/SymlinkResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c6d861a6675584f06f2f7692c060d6f4bf37d49
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/SymlinkResult.php
@@ -0,0 +1,24 @@
+rawResponse->header[OssClient::OSS_SYMLINK_TARGET] = rawurldecode($this->rawResponse->header[OssClient::OSS_SYMLINK_TARGET]);
+ return $this->rawResponse->header;
+ }
+}
+
diff --git a/addons/alioss/library/OSS/Result/UploadPartResult.php b/addons/alioss/library/OSS/Result/UploadPartResult.php
new file mode 100644
index 0000000000000000000000000000000000000000..c6b66d4547eae3031f6d5943e4cc0d797f97ff8b
--- /dev/null
+++ b/addons/alioss/library/OSS/Result/UploadPartResult.php
@@ -0,0 +1,28 @@
+rawResponse->header;
+ if (isset($header["etag"])) {
+ return $header["etag"];
+ }
+ throw new OssException("cannot get ETag");
+
+ }
+}
\ No newline at end of file
diff --git a/addons/cos/Cos.php b/addons/cos/Cos.php
new file mode 100644
index 0000000000000000000000000000000000000000..3d5214ba2381e26ebaa58f2e6edcb49bed766e27
--- /dev/null
+++ b/addons/cos/Cos.php
@@ -0,0 +1,98 @@
+getConfig();
+ $upload = [
+ 'cdnurl' => $cosConfig['cdnurl'],
+ 'uploadurl' => $cosConfig['uploadurl'],
+ 'bucket' => $cosConfig['bucket'],
+ 'maxsize' => $cosConfig['maxsize'],
+ 'mimetype' => $cosConfig['mimetype'],
+ 'multipart' => [],
+ 'multiple' => $cosConfig['multiple'] ? true : false,
+ ];
+ }
+
+ /**
+ * 附件删除后
+ */
+ public function uploadDelete($attachment)
+ {
+ $config = $this->getConfig();
+ if ($attachment['storage'] == 'cos' && isset($config['syncdelete']) && $config['syncdelete']) {
+ $url = $config['uploadurl'] . ltrim($attachment->url, '/');
+ list($authorization, $token) = Auth::getAuthorization('DELETE', ltrim($attachment->url, '/'));
+ //删除云储存文件
+ $ret = Http::sendRequest($url, [], 'DELETE', [CURLOPT_CUSTOMREQUEST => 'DELETE', CURLOPT_HTTPHEADER => ['Authorization: ' . $authorization, 'x-cos-security-token: ' . $token]]);
+ }
+ return true;
+ }
+}
diff --git a/addons/cos/assets/js/spark.js b/addons/cos/assets/js/spark.js
new file mode 100644
index 0000000000000000000000000000000000000000..5a22f703dcaaae60b2b165bee5031e72f42f2c58
--- /dev/null
+++ b/addons/cos/assets/js/spark.js
@@ -0,0 +1 @@
+(function(factory){if(typeof exports==="object"){module.exports=factory()}else if(typeof define==="function"&&define.amd){define(factory)}else{var glob;try{glob=window}catch(e){glob=self}glob.SparkMD5=factory()}})(function(undefined){"use strict";var add32=function(a,b){return a+b&4294967295},hex_chr=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];function cmn(q,a,b,x,s,t){a=add32(add32(a,q),add32(x,t));return add32(a<>>32-s,b)}function md5cycle(x,k){var a=x[0],b=x[1],c=x[2],d=x[3];a+=(b&c|~b&d)+k[0]-680876936|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[1]-389564586|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[2]+606105819|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[3]-1044525330|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[4]-176418897|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[5]+1200080426|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[6]-1473231341|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[7]-45705983|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[8]+1770035416|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[9]-1958414417|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[10]-42063|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[11]-1990404162|0;b=(b<<22|b>>>10)+c|0;a+=(b&c|~b&d)+k[12]+1804603682|0;a=(a<<7|a>>>25)+b|0;d+=(a&b|~a&c)+k[13]-40341101|0;d=(d<<12|d>>>20)+a|0;c+=(d&a|~d&b)+k[14]-1502002290|0;c=(c<<17|c>>>15)+d|0;b+=(c&d|~c&a)+k[15]+1236535329|0;b=(b<<22|b>>>10)+c|0;a+=(b&d|c&~d)+k[1]-165796510|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[6]-1069501632|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[11]+643717713|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[0]-373897302|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[5]-701558691|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[10]+38016083|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[15]-660478335|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[4]-405537848|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[9]+568446438|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[14]-1019803690|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[3]-187363961|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[8]+1163531501|0;b=(b<<20|b>>>12)+c|0;a+=(b&d|c&~d)+k[13]-1444681467|0;a=(a<<5|a>>>27)+b|0;d+=(a&c|b&~c)+k[2]-51403784|0;d=(d<<9|d>>>23)+a|0;c+=(d&b|a&~b)+k[7]+1735328473|0;c=(c<<14|c>>>18)+d|0;b+=(c&a|d&~a)+k[12]-1926607734|0;b=(b<<20|b>>>12)+c|0;a+=(b^c^d)+k[5]-378558|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[8]-2022574463|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[11]+1839030562|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[14]-35309556|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[1]-1530992060|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[4]+1272893353|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[7]-155497632|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[10]-1094730640|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[13]+681279174|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[0]-358537222|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[3]-722521979|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[6]+76029189|0;b=(b<<23|b>>>9)+c|0;a+=(b^c^d)+k[9]-640364487|0;a=(a<<4|a>>>28)+b|0;d+=(a^b^c)+k[12]-421815835|0;d=(d<<11|d>>>21)+a|0;c+=(d^a^b)+k[15]+530742520|0;c=(c<<16|c>>>16)+d|0;b+=(c^d^a)+k[2]-995338651|0;b=(b<<23|b>>>9)+c|0;a+=(c^(b|~d))+k[0]-198630844|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[7]+1126891415|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[14]-1416354905|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[5]-57434055|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[12]+1700485571|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[3]-1894986606|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[10]-1051523|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[1]-2054922799|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[8]+1873313359|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[15]-30611744|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[6]-1560198380|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[13]+1309151649|0;b=(b<<21|b>>>11)+c|0;a+=(c^(b|~d))+k[4]-145523070|0;a=(a<<6|a>>>26)+b|0;d+=(b^(a|~c))+k[11]-1120210379|0;d=(d<<10|d>>>22)+a|0;c+=(a^(d|~b))+k[2]+718787259|0;c=(c<<15|c>>>17)+d|0;b+=(d^(c|~a))+k[9]-343485551|0;b=(b<<21|b>>>11)+c|0;x[0]=a+x[0]|0;x[1]=b+x[1]|0;x[2]=c+x[2]|0;x[3]=d+x[3]|0}function md5blk(s){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=s.charCodeAt(i)+(s.charCodeAt(i+1)<<8)+(s.charCodeAt(i+2)<<16)+(s.charCodeAt(i+3)<<24)}return md5blks}function md5blk_array(a){var md5blks=[],i;for(i=0;i<64;i+=4){md5blks[i>>2]=a[i]+(a[i+1]<<8)+(a[i+2]<<16)+(a[i+3]<<24)}return md5blks}function md51(s){var n=s.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk(s.substring(i-64,i)))}s=s.substring(i-64);length=s.length;tail=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];for(i=0;i>2]|=s.charCodeAt(i)<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function md51_array(a){var n=a.length,state=[1732584193,-271733879,-1732584194,271733878],i,length,tail,tmp,lo,hi;for(i=64;i<=n;i+=64){md5cycle(state,md5blk_array(a.subarray(i-64,i)))}a=i-64>2]|=a[i]<<(i%4<<3)}tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(state,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=n*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(state,tail);return state}function rhex(n){var s="",j;for(j=0;j<4;j+=1){s+=hex_chr[n>>j*8+4&15]+hex_chr[n>>j*8&15]}return s}function hex(x){var i;for(i=0;i>16)+(y>>16)+(lsw>>16);return msw<<16|lsw&65535}}if(typeof ArrayBuffer!=="undefined"&&!ArrayBuffer.prototype.slice){(function(){function clamp(val,length){val=val|0||0;if(val<0){return Math.max(val+length,0)}return Math.min(val,length)}ArrayBuffer.prototype.slice=function(from,to){var length=this.byteLength,begin=clamp(from,length),end=length,num,target,targetArray,sourceArray;if(to!==undefined){end=clamp(to,length)}if(begin>end){return new ArrayBuffer(0)}num=end-begin;target=new ArrayBuffer(num);targetArray=new Uint8Array(target);sourceArray=new Uint8Array(this,begin,num);targetArray.set(sourceArray);return target}})()}function toUtf8(str){if(/[\u0080-\uFFFF]/.test(str)){str=unescape(encodeURIComponent(str))}return str}function utf8Str2ArrayBuffer(str,returnUInt8Array){var length=str.length,buff=new ArrayBuffer(length),arr=new Uint8Array(buff),i;for(i=0;i>2]|=buff.charCodeAt(i)<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.prototype.reset=function(){this._buff="";this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.prototype.getState=function(){return{buff:this._buff,length:this._length,hash:this._hash}};SparkMD5.prototype.setState=function(state){this._buff=state.buff;this._length=state.length;this._hash=state.hash;return this};SparkMD5.prototype.destroy=function(){delete this._hash;delete this._buff;delete this._length};SparkMD5.prototype._finish=function(tail,length){var i=length,tmp,lo,hi;tail[i>>2]|=128<<(i%4<<3);if(i>55){md5cycle(this._hash,tail);for(i=0;i<16;i+=1){tail[i]=0}}tmp=this._length*8;tmp=tmp.toString(16).match(/(.*?)(.{0,8})$/);lo=parseInt(tmp[2],16);hi=parseInt(tmp[1],16)||0;tail[14]=lo;tail[15]=hi;md5cycle(this._hash,tail)};SparkMD5.hash=function(str,raw){return SparkMD5.hashBinary(toUtf8(str),raw)};SparkMD5.hashBinary=function(content,raw){var hash=md51(content),ret=hex(hash);return raw?hexToBinaryString(ret):ret};SparkMD5.ArrayBuffer=function(){this.reset()};SparkMD5.ArrayBuffer.prototype.append=function(arr){var buff=concatenateArrayBuffers(this._buff.buffer,arr,true),length=buff.length,i;this._length+=arr.byteLength;for(i=64;i<=length;i+=64){md5cycle(this._hash,md5blk_array(buff.subarray(i-64,i)))}this._buff=i-64>2]|=buff[i]<<(i%4<<3)}this._finish(tail,length);ret=hex(this._hash);if(raw){ret=hexToBinaryString(ret)}this.reset();return ret};SparkMD5.ArrayBuffer.prototype.reset=function(){this._buff=new Uint8Array(0);this._length=0;this._hash=[1732584193,-271733879,-1732584194,271733878];return this};SparkMD5.ArrayBuffer.prototype.getState=function(){var state=SparkMD5.prototype.getState.call(this);state.buff=arrayBuffer2Utf8Str(state.buff);return state};SparkMD5.ArrayBuffer.prototype.setState=function(state){state.buff=utf8Str2ArrayBuffer(state.buff,true);return SparkMD5.prototype.setState.call(this,state)};SparkMD5.ArrayBuffer.prototype.destroy=SparkMD5.prototype.destroy;SparkMD5.ArrayBuffer.prototype._finish=SparkMD5.prototype._finish;SparkMD5.ArrayBuffer.hash=function(arr,raw){var hash=md51_array(new Uint8Array(arr)),ret=hex(hash);return raw?hexToBinaryString(ret):ret};return SparkMD5});
diff --git a/addons/cos/bootstrap.js b/addons/cos/bootstrap.js
new file mode 100644
index 0000000000000000000000000000000000000000..731de2f3bded515ed879ffe90edaab4ba3dfb9be
--- /dev/null
+++ b/addons/cos/bootstrap.js
@@ -0,0 +1,92 @@
+//修改上传的接口调用
+require(['upload', '../addons/cos/js/spark'], function (Upload, SparkMD5) {
+ var _onFileAdded = Upload.events.onFileAdded;
+ var _onUploadResponse = Upload.events.onUploadResponse;
+ var _process = function (up, file) {
+ (function (up, file) {
+ var blob = file.getNative();
+ var loadedBytes = file.loaded;
+ var chunkSize = 2097152;
+ var chunkBlob = blob.slice(loadedBytes, loadedBytes + chunkSize);
+ var reader = new FileReader();
+ reader.addEventListener('loadend', function (e) {
+ var spark = new SparkMD5.ArrayBuffer();
+ spark.append(e.target.result);
+ var md5 = spark.end();
+ Fast.api.ajax({
+ url: "/addons/cos/index/params",
+ data: {method: 'POST', md5: md5, name: file.name, type: file.type, size: file.size},
+ }, function (data) {
+ file.md5 = md5;
+ file.status = 1;
+ file.key = data.key;
+ file.filename = data.filename;
+ file.token = data.token;
+ file.signature = data.signature;
+ file.notifysignature = data.notifysignature;
+ up.start();
+ return false;
+ });
+ return;
+ });
+ reader.readAsArrayBuffer(chunkBlob);
+ })(up, file);
+ };
+ Upload.events.onFileAdded = function (up, files) {
+ return _onFileAdded.call(this, up, files);
+ };
+ Upload.events.onBeforeUpload = function (up, file) {
+ if (up.settings.url == Config.upload.uploadurl) {
+ if (typeof file.md5 === 'undefined') {
+ up.stop();
+ _process(up, file);
+ } else {
+ up.settings.headers = up.settings.headers || {};
+ up.settings.multipart_params.key = file.key;
+ up.settings.multipart_params.Signature = file.signature;
+ up.settings.multipart_params.success_action_status = 200;
+ up.settings.multipart_params['Content-Disposition'] = 'inline; filename=' + file.filename;
+ up.settings.multipart_params['Content-Type'] = file.type;
+ up.settings.multipart_params['x-cos-security-token'] = file.token;
+ up.settings.send_file_name = false;
+ }
+ }
+ };
+ Upload.events.onUploadResponse = function (response, info, up, file) {
+ if (up.settings.url == Config.upload.uploadurl) {
+ try {
+ var ret = {};
+ if (info.status === 200) {
+ var url = '/' + file.key;
+ Fast.api.ajax({
+ url: "/addons/cos/index/notify",
+ data: {
+ method: 'POST',
+ name: file.name,
+ url: url,
+ md5: file.md5,
+ size: file.size,
+ type: file.type,
+ signature: file.signature,
+ token: file.token,
+ notifysignature: file.notifysignature
+ }
+ }, function () {
+ return false;
+ });
+ ret.code = 1;
+ ret.data = {
+ url: url
+ };
+ } else {
+ ret.code = 0;
+ ret.msg = info.response;
+ }
+ return _onUploadResponse.call(this, JSON.stringify(ret));
+
+ } catch (e) {
+ }
+ }
+ return _onUploadResponse.call(this, response);
+ };
+});
\ No newline at end of file
diff --git a/addons/cos/config.php b/addons/cos/config.php
new file mode 100644
index 0000000000000000000000000000000000000000..abce612a364dd3e006d02a423b9d6d3c5cee05c0
--- /dev/null
+++ b/addons/cos/config.php
@@ -0,0 +1,173 @@
+ 'appid',
+ 'title' => 'AppID',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'your appid',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '请前往腾讯控制台 > 访问管理 > API密钥',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'secretid',
+ 'title' => 'SecretId',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'your secretid',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '请前往腾讯控制台 > 访问管理 > API密钥',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'secretkey',
+ 'title' => 'SecretKey',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'your secretkey',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '请前往腾讯控制台 > 访问管理 > API密钥',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'bucket',
+ 'title' => '存储桶名称',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'yourbucket-1234567890',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '存储空间名称',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'region',
+ 'title' => '地域名称',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'ap-guangzhou',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '请输入地域简称,请注意使用英文',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'uploadurl',
+ 'title' => '上传接口地址',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'https://yourbucket-1234567890.cos.ap-guangzhou.myqcloud.com/',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '请输入你的上传接口地址',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'cdnurl',
+ 'title' => 'CDN地址',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'https://yourbucket-1234567890.file.myqcloud.com',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '请配置你的CDN地址或在存储桶基础配置中获取',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'savekey',
+ 'title' => '保存文件名',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => '/uploads/{year}{mon}{day}/{filemd5}{.suffix}',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'expire',
+ 'title' => '上传有效时长',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => '600',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'maxsize',
+ 'title' => '最大可上传',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => '10M',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'mimetype',
+ 'title' => '可上传后缀格式',
+ 'type' => 'string',
+ 'content' =>
+ array(),
+ 'value' => 'jpg,png,bmp,jpeg,gif,zip,rar,xls,xlsx',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'multiple',
+ 'title' => '多文件上传',
+ 'type' => 'bool',
+ 'content' =>
+ array(),
+ 'value' => '0',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+ array(
+ 'name' => 'syncdelete',
+ 'title' => '附件删除时是否同步删除文件',
+ 'type' => 'bool',
+ 'content' =>
+ array(),
+ 'value' => '0',
+ 'rule' => 'required',
+ 'msg' => '',
+ 'tip' => '',
+ 'ok' => '',
+ 'extend' => '',
+ ),
+);
diff --git a/addons/cos/controller/Index.php b/addons/cos/controller/Index.php
new file mode 100644
index 0000000000000000000000000000000000000000..f19374d0de74ef2f1c48718e928e8bb8fca36f80
--- /dev/null
+++ b/addons/cos/controller/Index.php
@@ -0,0 +1,80 @@
+error("当前插件暂无前台页面");
+ }
+
+ public function params()
+ {
+ $config = get_addon_config('cos');
+ $name = $this->request->post('name');
+ $md5 = $this->request->post('md5');
+
+ $suffix = substr($name, stripos($name, '.') + 1);
+ $search = ['{year}', '{mon}', '{month}', '{day}', '{filemd5}', '{suffix}', '{.suffix}', '{filename}'];
+ $replace = [date("Y"), date("m"), date("m"), date("d"), $md5, $suffix, '.' . $suffix, $name];
+ $filename = ltrim(str_replace($search, $replace, $config['savekey']), '/');
+
+ list($signature, $token) = Auth::getAuthorization();
+ $params = [
+ 'key' => $filename,
+ 'filename' => basename($filename),
+ 'signature' => $signature,
+ 'token' => $token,
+ 'notifysignature' => md5($signature)
+ ];
+ $this->success('', null, $params);
+ return;
+ }
+
+ public function notify()
+ {
+ $size = $this->request->post('size');
+ $name = $this->request->post('name');
+ $md5 = $this->request->post('md5');
+ $type = $this->request->post('type');
+ $signature = $this->request->post('signature', '', 'trim');
+ $notifysignature = $this->request->post('notifysignature', '', 'trim');
+ $url = $this->request->post('url');
+ $suffix = substr($name, stripos($name, '.') + 1);
+ if ($notifysignature == md5($signature)) {
+ $attachment = Attachment::getBySha1($md5);
+ if (!$attachment) {
+ $params = array(
+ 'admin_id' => (int)session('admin.id'),
+ 'user_id' => (int)cookie('uid'),
+ 'filesize' => $size,
+ 'imagewidth' => 0,
+ 'imageheight' => 0,
+ 'imagetype' => $suffix,
+ 'imageframes' => 0,
+ 'mimetype' => $type,
+ 'url' => $url,
+ 'uploadtime' => time(),
+ 'storage' => 'cos',
+ 'sha1' => $md5,
+ );
+ Attachment::create($params);
+ }
+ $this->success();
+ } else {
+ $this->error(__('You have no permission'));
+ }
+ return;
+ }
+
+}
diff --git a/addons/cos/info.ini b/addons/cos/info.ini
new file mode 100644
index 0000000000000000000000000000000000000000..475e42ada8b09250b158414412e3be51b9fec4bd
--- /dev/null
+++ b/addons/cos/info.ini
@@ -0,0 +1,8 @@
+name = cos
+title = 腾讯COS云存储
+intro = 腾讯COS云存储插件
+author = Karson
+website = https://www.fastadmin.net
+version = 1.0.3
+state = 1
+url = /fastadmin/my/public/addons/cos
diff --git a/addons/cos/library/Auth.php b/addons/cos/library/Auth.php
new file mode 100644
index 0000000000000000000000000000000000000000..19c7045a68e38e6dad8993f4f1f520c66effab44
--- /dev/null
+++ b/addons/cos/library/Auth.php
@@ -0,0 +1,242 @@
+ $val) {
+ array_push($arr, $key . '=' . $val);
+ }
+ return join('&', $arr);
+ }
+
+ // 计算临时密钥用的签名
+ private static function getSignature($opt, $key, $method)
+ {
+ $formatString = $method . self::DOMAIN . '/v2/index.php?' . self::json2str($opt);
+ $sign = hash_hmac('sha1', $formatString, $key);
+ $sign = base64_encode(hex2bin($sign));
+ return $sign;
+ }
+
+ // 获取临时密钥
+ private static function getTempKeys()
+ {
+ $cosConfig = get_addon_config('cos');
+ $config = array(
+ 'Url' => self::STSURL,
+ 'Domain' => self::DOMAIN,
+ 'Proxy' => '',
+ 'SecretId' => $cosConfig['secretid'], // 固定密钥
+ 'SecretKey' => $cosConfig['secretkey'], // 固定密钥
+ 'Bucket' => $cosConfig['bucket'],
+ 'Region' => $cosConfig['region'],
+ 'AllowPrefix' => '*', // 这里改成允许的路径前缀,这里可以根据自己网站的用户登录态判断允许上传的目录,例子:* 或者 a/* 或者 a.jpg
+ );
+
+ $ShortBucketName = substr($config['Bucket'], 0, strripos($config['Bucket'], '-'));
+ $AppId = substr($config['Bucket'], 1 + strripos($config['Bucket'], '-'));
+ $policy = array(
+ 'version' => '2.0',
+ 'statement' => array(
+ array(
+ 'action' => array(
+ // // 这里可以从临时密钥的权限上控制前端允许的操作
+ // 'name/cos:*', // 这样写可以包含下面所有权限
+
+ // // 列出所有允许的操作
+ // // ACL 读写
+ // 'name/cos:GetBucketACL',
+ // 'name/cos:PutBucketACL',
+ // 'name/cos:GetObjectACL',
+ // 'name/cos:PutObjectACL',
+ // // 简单 Bucket 操作
+ // 'name/cos:PutBucket',
+ // 'name/cos:HeadBucket',
+ // 'name/cos:GetBucket',
+ // 'name/cos:DeleteBucket',
+ // 'name/cos:GetBucketLocation',
+ // // Versioning
+ // 'name/cos:PutBucketVersioning',
+ // 'name/cos:GetBucketVersioning',
+ // // CORS
+ // 'name/cos:PutBucketCORS',
+ // 'name/cos:GetBucketCORS',
+ // 'name/cos:DeleteBucketCORS',
+ // // Lifecycle
+ // 'name/cos:PutBucketLifecycle',
+ // 'name/cos:GetBucketLifecycle',
+ // 'name/cos:DeleteBucketLifecycle',
+ // // Replication
+ // 'name/cos:PutBucketReplication',
+ // 'name/cos:GetBucketReplication',
+ // 'name/cos:DeleteBucketReplication',
+ // // 删除文件
+ // 'name/cos:DeleteMultipleObject',
+ 'name/cos:DeleteObject',
+ // 简单文件操作
+ 'name/cos:PutObject',
+ 'name/cos:PostObject',
+ 'name/cos:AppendObject',
+ 'name/cos:GetObject',
+ 'name/cos:HeadObject',
+ 'name/cos:OptionsObject',
+ 'name/cos:PutObjectCopy',
+ 'name/cos:PostObjectRestore',
+ // 分片上传操作
+ 'name/cos:InitiateMultipartUpload',
+ 'name/cos:ListMultipartUploads',
+ 'name/cos:ListParts',
+ 'name/cos:UploadPart',
+ 'name/cos:CompleteMultipartUpload',
+ 'name/cos:AbortMultipartUpload',
+ ),
+ 'effect' => 'allow',
+ 'principal' => array('qcs' => array('*')),
+ 'resource' => array(
+ 'qcs::cos:' . $config['Region'] . ':uid/' . $AppId . ':prefix//' . $AppId . '/' . $ShortBucketName . '/',
+ 'qcs::cos:' . $config['Region'] . ':uid/' . $AppId . ':prefix//' . $AppId . '/' . $ShortBucketName . '/' . $config['AllowPrefix']
+ )
+ )
+ )
+ );
+
+ $policyStr = str_replace('\\/', '/', json_encode($policy));
+
+ // 有效时间小于 30 秒就重新获取临时密钥,否则使用缓存的临时密钥
+ if (isset($_SESSION['tempKeysCache']) && isset($_SESSION['tempKeysCache']['expiredTime']) && isset($_SESSION['tempKeysCache']['policyStr']) &&
+ $_SESSION['tempKeysCache']['expiredTime'] - time() > 30 && $_SESSION['tempKeysCache']['policyStr'] === $policyStr) {
+ return $_SESSION['tempKeysCache'];
+ }
+
+ $Action = 'GetFederationToken';
+ $Nonce = rand(10000, 20000);
+ $Timestamp = time() - 1;
+ $Method = 'GET';
+
+ $params = array(
+ 'Action' => $Action,
+ 'Nonce' => $Nonce,
+ 'Region' => '',
+ 'SecretId' => $config['SecretId'],
+ 'Timestamp' => $Timestamp,
+ 'durationSeconds' => 7200,
+ 'name' => '',
+ 'policy' => $policyStr
+ );
+ $params['Signature'] = urlencode(self::getSignature($params, $config['SecretKey'], $Method));
+ $url = $config['Url'] . '?' . self::json2str($params);
+ $ch = curl_init($url);
+ $config['Proxy'] && curl_setopt($ch, CURLOPT_PROXY, $config['Proxy']);
+ curl_setopt($ch, CURLOPT_HEADER, 0);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
+ $result = curl_exec($ch);
+ if (curl_errno($ch)) $result = curl_error($ch);
+ curl_close($ch);
+
+ $result = json_decode($result, 1);
+ if (isset($result['data'])) $result = $result['data'];
+
+ $_SESSION['tempKeysCache'] = $result;
+ $_SESSION['tempKeysCache']['policyStr'] = $policyStr;
+
+ return $result;
+ }
+}
\ No newline at end of file
diff --git a/addons/nkeditor/Nkeditor.php b/addons/nkeditor/Nkeditor.php
new file mode 100644
index 0000000000000000000000000000000000000000..c10e1b79cbb23d7dcabbe3b4e80c61de7e0b0bd0
--- /dev/null
+++ b/addons/nkeditor/Nkeditor.php
@@ -0,0 +1,63 @@
+getConfig();
+ $params['nkeditor'] = ['theme' => $config['theme']];
+ }
+
+}
diff --git a/addons/nkeditor/README.md b/addons/nkeditor/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..6ee75c73575df38d7b42bc56f50a8c5249379375
--- /dev/null
+++ b/addons/nkeditor/README.md
@@ -0,0 +1,17 @@
+# NKeditor
+NKedtior是基于 kindeditor 进行二次开发的项目
+kindeditor 是一款优秀的开源在线编辑器。轻量级且功能强大,代码量却不到百度的ueditor编辑器的一半。可惜已经4年没有更新了,由于业务的需求我们在kindeditor的基础上开发了 NKeditor, 主要做了一下工作:
+1. 调整编辑器和弹出 dialog 的样式,美化了UI
+2. 重写图片上传和批量图片上传插件,使用 html5 上传代替了 flash,实现了待上传图片预览,优化用户体验
+3. 修复一些已知的bug,如 ajax 提交无法获取内容等
+4. 新增涂鸦等功能
+
+再次感谢 kindeditor 的开发者,为我们提供了如此优秀的在线编辑器,让我们能在前人的基础上继续贡献自己的微薄之力。
+
+# 开源说明
+本插件基于Nkeditor进行二次开发,修改的核心文件已开源于 https://gitee.com/karson/kindeditor
+
+# 特别感谢
+[Kindeditor](https://gitee.com/luolonghao/kindeditor)
+[Nkeditor](https://gitee.com/blackfox/kindeditor)
+
diff --git a/addons/nkeditor/assets/css/common.css b/addons/nkeditor/assets/css/common.css
new file mode 100644
index 0000000000000000000000000000000000000000..12fa84ef15bafb41f02241244354476d84ef7567
--- /dev/null
+++ b/addons/nkeditor/assets/css/common.css
@@ -0,0 +1,5 @@
+
+.ke-container-black .ke-toolbar .ke-icon-remoteimage {
+ background-image: url(../img/download.png);
+ background-size: 16px 16px;
+}
\ No newline at end of file
diff --git a/addons/nkeditor/assets/img/download.png b/addons/nkeditor/assets/img/download.png
new file mode 100644
index 0000000000000000000000000000000000000000..1945ae7792909fc55eeff0353029ca2beb410822
Binary files /dev/null and b/addons/nkeditor/assets/img/download.png differ
diff --git a/addons/nkeditor/assets/img/downloading.png b/addons/nkeditor/assets/img/downloading.png
new file mode 100644
index 0000000000000000000000000000000000000000..1d6cbd1e13b01904c430f35cbf9c3aa292258c52
Binary files /dev/null and b/addons/nkeditor/assets/img/downloading.png differ
diff --git a/addons/nkeditor/assets/js/customplugin.js b/addons/nkeditor/assets/js/customplugin.js
new file mode 100644
index 0000000000000000000000000000000000000000..79075e9369d26be69c089432b2805aa4a56fa229
--- /dev/null
+++ b/addons/nkeditor/assets/js/customplugin.js
@@ -0,0 +1,74 @@
+define(['nkeditor-core'], function (Nkeditor) {
+ Nkeditor.plugin('multiimage', function (K) {
+ var self = this, name = 'multiimage', lang = self.lang(name + '.'),
+ allowImages = K.undef(self.allowImages, false);
+
+ var click = function () {
+
+ var html = [
+ ''
+ ].join('');
+ var dialog = self.createDialog({
+ name: name,
+ width: 450,
+ height: 260,
+ title: self.lang(name),
+ body: html,
+ noBtn: {
+ name: self.lang('no'),
+ click: function (e) {
+ self.hideDialog().focus();
+ }
+ }
+ }),
+ div = dialog.div;
+ $("input[name=imgFiles]", div).change(function () {
+ dialog.showLoading();
+ var files = $(this).prop('files');
+ $.each(files, function (i, file) {
+ self.beforeUpload.call(self, function (data) {
+ self.exec('insertimage', Fast.api.cdnurl(data.data.url));
+ }, file);
+ });
+ setTimeout(function () {
+ self.hideDialog().focus();
+ }, 0);
+ });
+ $(".ke-select-image", div).click(function () {
+ self.loadPlugin('filemanager', function () {
+ self.plugin.filemanagerDialog({
+ dirName: 'image',
+ multiple: true,
+ clickFn: function (urls) {
+ $.each(urls, function(i, url){
+ self.exec('insertimage', url);
+ });
+ }
+ });
+ });
+ self.hideDialog().focus();
+ // parent.Fast.api.open("general/attachment/select?element_id=&multiple=true&mimetype=*", __('Choose'), {
+ // callback: function (data) {
+ // var urlArr = data.url.split(/\,/);
+ // $.each(urlArr, function () {
+ // var url = Fast.api.cdnurl(this);
+ // self.exec('insertimage', url);
+ // });
+ // }
+ // });
+ });
+ };
+ self.clickToolbar(name, click);
+ });
+
+ return Nkeditor;
+});
diff --git a/addons/nkeditor/assets/lang/ar.js b/addons/nkeditor/assets/lang/ar.js
new file mode 100644
index 0000000000000000000000000000000000000000..6eb4b7e3ac69e8f2525a793b07e338030be5764a
--- /dev/null
+++ b/addons/nkeditor/assets/lang/ar.js
@@ -0,0 +1,242 @@
+/*******************************************************************************
+* KindEditor - WYSIWYG HTML Editor for Internet
+* Copyright (C) 2006-2011 kindsoft.net
+*
+* @author Roddy
+* @site http://www.kindsoft.net/
+* @licence http://www.kindsoft.net/license.php
+* Arabic Translation By daif alotaibi (http://daif.net/)
+*******************************************************************************/
+
+KindEditor.lang({
+ source : 'عرض المصدر',
+ preview : 'معاينة الصفحة',
+ undo : 'تراجع(Ctrl+Z)',
+ redo : 'إعادة التراجع(Ctrl+Y)',
+ cut : 'قص(Ctrl+X)',
+ copy : 'نسخ(Ctrl+C)',
+ paste : 'لصق(Ctrl+V)',
+ plainpaste : 'لصق كنص عادي',
+ wordpaste : 'لصق من مايكروسفت ورد',
+ selectall : 'تحديد الكل',
+ justifyleft : 'محاذاه لليسار',
+ justifycenter : 'محاذاه للوسط',
+ justifyright : 'محاذاه لليمين',
+ justifyfull : 'محاذاه تلقائية',
+ insertorderedlist : 'قائمة مرقمه',
+ insertunorderedlist : 'قائمة نقطية',
+ indent : 'إزاحه النص',
+ outdent : 'إلغاء الازاحة',
+ subscript : 'أسفل النص',
+ superscript : 'أعلى النص',
+ formatblock : 'Paragraph format',
+ fontname : 'نوع الخط',
+ fontsize : 'حجم الخط',
+ forecolor : 'لون النص',
+ hilitecolor : 'لون خلفية النص',
+ bold : 'عريض(Ctrl+B)',
+ italic : 'مائل(Ctrl+I)',
+ underline : 'خط تحت النص(Ctrl+U)',
+ strikethrough : 'خط على النص',
+ removeformat : 'إزالة التنسيق',
+ image : 'إدراج صورة',
+ multiimage : 'Multi image',
+ flash : 'إدراج فلاش',
+ media : 'إدراج وسائط متعددة',
+ table : 'إدراج جدول',
+ tablecell : 'خلية',
+ hr : 'إدراج خط أفقي',
+ emoticons : 'إدراج وجه ضاحك',
+ link : 'رابط',
+ unlink : 'إزالة الرابط',
+ fullscreen : 'محرر ملئ الشاشة',
+ about : 'حول',
+ print : 'طباعة',
+ filemanager : 'مدير الملفات',
+ code : 'إدراج نص برمجي',
+ map : 'خرائط قووقل',
+ baidumap : 'خرائط قووقل',
+ lineheight : 'إرتفاع السطر',
+ clearhtml : 'مسح كود HTML',
+ pagebreak : 'إدراج فاصل صفحات',
+ quickformat : 'تنسيق سريع',
+ insertfile : 'إدراج ملف',
+ template : 'إدراج قالب',
+ anchor : 'رابط',
+ yes : 'موافق',
+ no : 'إلغاء',
+ close : 'إغلاق',
+ editImage : 'خصائص الصورة',
+ deleteImage : 'حذفالصورة',
+ editFlash : 'خصائص الفلاش',
+ deleteFlash : 'حذف الفلاش',
+ editMedia : 'خصائص الوسائط',
+ deleteMedia : 'حذف الوسائط',
+ editLink : 'خصائص الرابط',
+ deleteLink : 'إزالة الرابط',
+ editAnchor : 'Anchor properties',
+ deleteAnchor : 'Delete Anchor',
+ tableprop : 'خصائص الجدول',
+ tablecellprop : 'خصائص الخلية',
+ tableinsert : 'إدراج جدول',
+ tabledelete : 'حذف جدول',
+ tablecolinsertleft : 'إدراج عمود لليسار',
+ tablecolinsertright : 'إدراج عمود لليسار',
+ tablerowinsertabove : 'إدراج صف للأعلى',
+ tablerowinsertbelow : 'إدراج صف للأسفل',
+ tablerowmerge : 'دمج للأسفل',
+ tablecolmerge : 'دمج لليمين',
+ tablerowsplit : 'تقسم الصف',
+ tablecolsplit : 'تقسيم العمود',
+ tablecoldelete : 'حذف العمود',
+ tablerowdelete : 'حذف الصف',
+ noColor : 'إفتراضي',
+ pleaseSelectFile : 'Please select file.',
+ invalidImg : "الرجاء إدخال رابط صحيح.\nالملفات المسموح بها: jpg,gif,bmp,png",
+ invalidMedia : "الرجاء إدخال رابط صحيح.\nالملفات المسموح بها: swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb",
+ invalidWidth : "العرض يجب أن يكون رقم.",
+ invalidHeight : "الإرتفاع يجب أن يكون رقم.",
+ invalidBorder : "عرض الحد يجب أن يكون رقم.",
+ invalidUrl : "الرجاء إدخال رابط حيح.",
+ invalidRows : 'صفوف غير صحيح.',
+ invalidCols : 'أعمدة غير صحيحة.',
+ invalidPadding : 'The padding must be number.',
+ invalidSpacing : 'The spacing must be number.',
+ invalidJson : 'Invalid JSON string.',
+ uploadSuccess : 'تم رفع الملف بنجاح.',
+ cutError : 'حاليا غير مدعومة من المتصفح, إستخدم إختصار لوحة المفاتيح (Ctrl+X).',
+ copyError : 'حاليا غير مدعومة من المتصفح, إستخدم إختصار لوحة المفاتيح (Ctrl+C).',
+ pasteError : 'حاليا غير مدعومة من المتصفح, إستخدم إختصار لوحة المفاتيح (Ctrl+V).',
+ ajaxLoading : 'Loading ...',
+ uploadLoading : 'Uploading ...',
+ uploadError : 'Upload Error',
+ 'plainpaste.comment' : 'إستخدم إختصار لوحة المفاتيح (Ctrl+V) للصق داخل النافذة.',
+ 'wordpaste.comment' : 'إستخدم إختصار لوحة المفاتيح (Ctrl+V) للصق داخل النافذة.',
+ 'code.pleaseInput' : 'Please input code.',
+ 'link.url' : 'الرابط',
+ 'link.linkType' : 'الهدف',
+ 'link.newWindow' : 'نافذة جديدة',
+ 'link.selfWindow' : 'نفس النافذة',
+ 'flash.url' : 'الرابط',
+ 'flash.width' : 'العرض',
+ 'flash.height' : 'الإرتفاع',
+ 'flash.upload' : 'رفع',
+ 'flash.viewServer' : 'أستعراض',
+ 'media.url' : 'الرابط',
+ 'media.width' : 'العرض',
+ 'media.height' : 'الإرتفاع',
+ 'media.autostart' : 'تشغيل تلقائي',
+ 'media.upload' : 'رفع',
+ 'media.viewServer' : 'أستعراض',
+ 'image.remoteImage' : 'إدراج الرابط',
+ 'image.localImage' : 'رفع',
+ 'image.remoteUrl' : 'الرابط',
+ 'image.localUrl' : 'الملف',
+ 'image.size' : 'الحجم',
+ 'image.width' : 'العرض',
+ 'image.height' : 'الإرتفاع',
+ 'image.resetSize' : 'إستعادة الأبعاد',
+ 'image.align' : 'محاذاة',
+ 'image.defaultAlign' : 'الإفتراضي',
+ 'image.leftAlign' : 'اليسار',
+ 'image.rightAlign' : 'اليمين',
+ 'image.imgTitle' : 'العنوان',
+ 'image.upload' : 'أستعراض',
+ 'image.viewServer' : 'أستعراض',
+ 'multiimage.uploadDesc' : 'Allows users to upload <%=uploadLimit%> images, single image size not exceeding <%=sizeLimit%>',
+ 'multiimage.startUpload' : 'Start upload',
+ 'multiimage.clearAll' : 'Clear all',
+ 'multiimage.insertAll' : 'Insert all',
+ 'multiimage.queueLimitExceeded' : 'Queue limit exceeded.',
+ 'multiimage.fileExceedsSizeLimit' : 'File exceeds size limit.',
+ 'multiimage.zeroByteFile' : 'Zero byte file.',
+ 'multiimage.invalidFiletype' : 'Invalid file type.',
+ 'multiimage.unknownError' : 'Unknown upload error.',
+ 'multiimage.pending' : 'Pending ...',
+ 'multiimage.uploadError' : 'Upload error',
+ 'filemanager.emptyFolder' : 'فارغ',
+ 'filemanager.moveup' : 'المجلد الأب',
+ 'filemanager.viewType' : 'العرض: ',
+ 'filemanager.viewImage' : 'مصغرات',
+ 'filemanager.listImage' : 'قائمة',
+ 'filemanager.orderType' : 'الترتيب: ',
+ 'filemanager.fileName' : 'بالإسم',
+ 'filemanager.fileSize' : 'بالحجم',
+ 'filemanager.fileType' : 'بالنوع',
+ 'insertfile.url' : 'الرابط',
+ 'insertfile.title' : 'العنوان',
+ 'insertfile.upload' : 'رفع',
+ 'insertfile.viewServer' : 'أستعراض',
+ 'table.cells' : 'خلايا',
+ 'table.rows' : 'صفوف',
+ 'table.cols' : 'أعمدة',
+ 'table.size' : 'الأبعاد',
+ 'table.width' : 'العرض',
+ 'table.height' : 'الإرتفاع',
+ 'table.percent' : '%',
+ 'table.px' : 'px',
+ 'table.space' : 'الخارج',
+ 'table.padding' : 'الداخل',
+ 'table.spacing' : 'الفراغات',
+ 'table.align' : 'محاذاه',
+ 'table.textAlign' : 'افقى',
+ 'table.verticalAlign' : 'رأسي',
+ 'table.alignDefault' : 'إفتراضي',
+ 'table.alignLeft' : 'يسار',
+ 'table.alignCenter' : 'وسط',
+ 'table.alignRight' : 'يمين',
+ 'table.alignTop' : 'أعلى',
+ 'table.alignMiddle' : 'منتصف',
+ 'table.alignBottom' : 'أسفل',
+ 'table.alignBaseline' : 'Baseline',
+ 'table.border' : 'الحدود',
+ 'table.borderWidth' : 'العرض',
+ 'table.borderColor' : 'اللون',
+ 'table.backgroundColor' : 'الخلفية',
+ 'map.address' : 'العنوان: ',
+ 'map.search' : 'بحث',
+ 'baidumap.address' : 'العنوان: ',
+ 'baidumap.search' : 'بحث',
+ 'baidumap.insertDynamicMap' : 'Dynamic Map',
+ 'anchor.name' : 'إسم الرابط',
+ 'formatblock.formatBlock' : {
+ h1 : 'عنوان 1',
+ h2 : 'عنوان 2',
+ h3 : 'عنوان 3',
+ h4 : 'عنوان 4',
+ p : 'عادي'
+ },
+ 'fontname.fontName' : {
+ 'Arial' : 'Arial',
+ 'Arial Black' : 'Arial Black',
+ 'Comic Sans MS' : 'Comic Sans MS',
+ 'Courier New' : 'Courier New',
+ 'Garamond' : 'Garamond',
+ 'Georgia' : 'Georgia',
+ 'Tahoma' : 'Tahoma',
+ 'Times New Roman' : 'Times New Roman',
+ 'Trebuchet MS' : 'Trebuchet MS',
+ 'Verdana' : 'Verdana'
+ },
+ 'lineheight.lineHeight' : [
+ {'1' : 'إرتفاع السطر 1'},
+ {'1.5' : 'إرتفاع السطر 1.5'},
+ {'2' : 'إرتفاع السطر 2'},
+ {'2.5' : 'إرتفاع السطر 2.5'},
+ {'3' : 'إرتفاع السطر 3'}
+ ],
+ 'template.selectTemplate' : 'قالب',
+ 'template.replaceContent' : 'إستبدال المحتوى الحالي',
+ 'template.fileList' : {
+ '1.html' : 'صورة ونص',
+ '2.html' : 'جدول',
+ '3.html' : 'قائمة'
+ }
+}, 'ar');
+
+KindEditor.each(KindEditor.options.items, function(i, name) {
+ if (name == 'baidumap') {
+ KindEditor.options.items[i] = 'map';
+ }
+});
+KindEditor.options.langType = 'ar';
\ No newline at end of file
diff --git a/addons/nkeditor/assets/lang/en.js b/addons/nkeditor/assets/lang/en.js
new file mode 100644
index 0000000000000000000000000000000000000000..dbaa616b1519f5d23109cd9f9739f5956fcb7dcb
--- /dev/null
+++ b/addons/nkeditor/assets/lang/en.js
@@ -0,0 +1,243 @@
+/*******************************************************************************
+* KindEditor - WYSIWYG HTML Editor for Internet
+* Copyright (C) 2006-2011 kindsoft.net
+*
+* @author Roddy
+* @site http://www.kindsoft.net/
+* @licence http://www.kindsoft.net/license.php
+*******************************************************************************/
+
+KindEditor.lang({
+ source : 'Source',
+ preview : 'Preview',
+ undo : 'Undo(Ctrl+Z)',
+ redo : 'Redo(Ctrl+Y)',
+ cut : 'Cut(Ctrl+X)',
+ copy : 'Copy(Ctrl+C)',
+ paste : 'Paste(Ctrl+V)',
+ plainpaste : 'Paste as plain text',
+ wordpaste : 'Paste from Word',
+ selectall : 'Select all',
+ justifyleft : 'Align left',
+ justifycenter : 'Align center',
+ justifyright : 'Align right',
+ justifyfull : 'Align full',
+ insertorderedlist : 'Ordered list',
+ insertunorderedlist : 'Unordered list',
+ indent : 'Increase indent',
+ outdent : 'Decrease indent',
+ subscript : 'Subscript',
+ superscript : 'Superscript',
+ formatblock : 'Paragraph format',
+ fontname : 'Font family',
+ fontsize : 'Font size',
+ forecolor : 'Text color',
+ hilitecolor : 'Highlight color',
+ bold : 'Bold(Ctrl+B)',
+ italic : 'Italic(Ctrl+I)',
+ underline : 'Underline(Ctrl+U)',
+ strikethrough : 'Strikethrough',
+ removeformat : 'Remove format',
+ image : 'Image',
+ multiimage : 'Multi image',
+ flash : 'Flash',
+ media : 'Embeded media',
+ table : 'Table',
+ tablecell : 'Cell',
+ hr : 'Insert horizontal line',
+ emoticons : 'Insert emoticon',
+ link : 'Link',
+ unlink : 'Unlink',
+ fullscreen : 'Toggle fullscreen mode',
+ about : 'About',
+ print : 'Print',
+ filemanager : 'File Manager',
+ code : 'Insert code',
+ map : 'Google Maps',
+ baidumap : 'Baidu Maps',
+ lineheight : 'Line height',
+ clearhtml : 'Clear HTML code',
+ pagebreak : 'Insert Page Break',
+ quickformat : 'Quick Format',
+ insertfile : 'Insert file',
+ template : 'Insert Template',
+ anchor : 'Anchor',
+ yes : 'OK',
+ no : 'Cancel',
+ close : 'Close',
+ editImage : 'Image properties',
+ deleteImage : 'Delete image',
+ editFlash : 'Flash properties',
+ deleteFlash : 'Delete flash',
+ editMedia : 'Media properties',
+ deleteMedia : 'Delete media',
+ editLink : 'Link properties',
+ deleteLink : 'Unlink',
+ editAnchor : 'Anchor properties',
+ deleteAnchor : 'Delete Anchor',
+ tableprop : 'Table properties',
+ tablecellprop : 'Cell properties',
+ tableinsert : 'Insert table',
+ tabledelete : 'Delete table',
+ tablecolinsertleft : 'Insert column left',
+ tablecolinsertright : 'Insert column right',
+ tablerowinsertabove : 'Insert row above',
+ tablerowinsertbelow : 'Insert row below',
+ tablerowmerge : 'Merge down',
+ tablecolmerge : 'Merge right',
+ tablerowsplit : 'Split row',
+ tablecolsplit : 'Split column',
+ tablecoldelete : 'Delete column',
+ tablerowdelete : 'Delete row',
+ noColor : 'Default',
+ pleaseSelectFile : 'Please select file.',
+ invalidImg : "Please type valid URL.\nAllowed file extension: jpg,gif,bmp,png",
+ invalidMedia : "Please type valid URL.\nAllowed file extension: swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb",
+ invalidWidth : "The width must be number.",
+ invalidHeight : "The height must be number.",
+ invalidBorder : "The border must be number.",
+ invalidUrl : "Please type valid URL.",
+ invalidRows : 'Invalid rows.',
+ invalidCols : 'Invalid columns.',
+ invalidPadding : 'The padding must be number.',
+ invalidSpacing : 'The spacing must be number.',
+ invalidJson : 'Invalid JSON string.',
+ uploadSuccess : 'Upload success.',
+ cutError : 'Currently not supported by your browser, use keyboard shortcut(Ctrl+X) instead.',
+ copyError : 'Currently not supported by your browser, use keyboard shortcut(Ctrl+C) instead.',
+ pasteError : 'Currently not supported by your browser, use keyboard shortcut(Ctrl+V) instead.',
+ ajaxLoading : 'Loading ...',
+ uploadLoading : 'Uploading ...',
+ uploadError : 'Upload Error',
+ 'plainpaste.comment' : 'Use keyboard shortcut(Ctrl+V) to paste the text into the window.',
+ 'wordpaste.comment' : 'Use keyboard shortcut(Ctrl+V) to paste the text into the window.',
+ 'code.pleaseInput' : 'Please input code.',
+ 'link.url' : 'URL',
+ 'link.linkType' : 'Target',
+ 'link.newWindow' : 'New window',
+ 'link.selfWindow' : 'Same window',
+ 'flash.url' : 'URL',
+ 'flash.width' : 'Width',
+ 'flash.height' : 'Height',
+ 'flash.upload' : 'Upload',
+ 'flash.viewServer' : 'Browse',
+ 'media.url' : 'URL',
+ 'media.width' : 'Width',
+ 'media.height' : 'Height',
+ 'media.autostart' : 'Auto start',
+ 'media.upload' : 'Upload',
+ 'media.viewServer' : 'Browse',
+ 'image.remoteImage' : 'Insert URL',
+ 'image.localImage' : 'Upload',
+ 'image.remoteUrl' : 'URL',
+ 'image.localUrl' : 'File',
+ 'image.size' : 'Size',
+ 'image.width' : 'Width',
+ 'image.height' : 'Height',
+ 'image.resetSize' : 'Reset dimensions',
+ 'image.align' : 'Align',
+ 'image.defaultAlign' : 'Default',
+ 'image.leftAlign' : 'Left',
+ 'image.rightAlign' : 'Right',
+ 'image.imgTitle' : 'Title',
+ 'image.upload' : 'Browse',
+ 'image.viewServer' : 'Browse',
+ 'multiimage.uploadDesc' : 'Allows users to upload <%=uploadLimit%> images, single image size not exceeding <%=sizeLimit%>',
+ 'multiimage.startUpload' : 'Start upload',
+ 'multiimage.clearAll' : 'Clear all',
+ 'multiimage.insertAll' : 'Insert all',
+ 'multiimage.queueLimitExceeded' : 'Queue limit exceeded.',
+ 'multiimage.fileExceedsSizeLimit' : 'File exceeds size limit.',
+ 'multiimage.zeroByteFile' : 'Zero byte file.',
+ 'multiimage.invalidFiletype' : 'Invalid file type.',
+ 'multiimage.unknownError' : 'Unknown upload error.',
+ 'multiimage.pending' : 'Pending ...',
+ 'multiimage.uploadError' : 'Upload error',
+ 'filemanager.emptyFolder' : 'Blank',
+ 'filemanager.moveup' : 'Parent folder',
+ 'filemanager.viewType' : 'Display: ',
+ 'filemanager.viewImage' : 'Thumbnails',
+ 'filemanager.listImage' : 'List',
+ 'filemanager.orderType' : 'Sorting: ',
+ 'filemanager.fileName' : 'By name',
+ 'filemanager.fileSize' : 'By size',
+ 'filemanager.fileType' : 'By type',
+ 'insertfile.url' : 'URL',
+ 'insertfile.title' : 'Title',
+ 'insertfile.upload' : 'Upload',
+ 'insertfile.viewServer' : 'Browse',
+ 'table.cells' : 'Cells',
+ 'table.rows' : 'Rows',
+ 'table.cols' : 'Columns',
+ 'table.size' : 'Dimensions',
+ 'table.width' : 'Width',
+ 'table.height' : 'Height',
+ 'table.percent' : '%',
+ 'table.px' : 'px',
+ 'table.space' : 'Space',
+ 'table.padding' : 'Padding',
+ 'table.spacing' : 'Spacing',
+ 'table.align' : 'Align',
+ 'table.textAlign' : 'Horizontal',
+ 'table.verticalAlign' : 'Vertical',
+ 'table.alignDefault' : 'Default',
+ 'table.alignLeft' : 'Left',
+ 'table.alignCenter' : 'Center',
+ 'table.alignRight' : 'Right',
+ 'table.alignTop' : 'Top',
+ 'table.alignMiddle' : 'Middle',
+ 'table.alignBottom' : 'Bottom',
+ 'table.alignBaseline' : 'Baseline',
+ 'table.border' : 'Border',
+ 'table.borderWidth' : 'Width',
+ 'table.borderColor' : 'Color',
+ 'table.backgroundColor' : 'Background',
+ 'map.address' : 'Address: ',
+ 'map.search' : 'Search',
+ 'baidumap.address' : 'Address: ',
+ 'baidumap.search' : 'Search',
+ 'baidumap.insertDynamicMap' : 'Dynamic Map',
+ 'anchor.name' : 'Anchor name',
+ 'formatblock.formatBlock' : {
+ h1 : 'Heading 1',
+ h2 : 'Heading 2',
+ h3 : 'Heading 3',
+ h4 : 'Heading 4',
+ p : 'Normal'
+ },
+ 'fontname.fontName' : {
+ 'Arial' : 'Arial',
+ 'Arial Black' : 'Arial Black',
+ 'Comic Sans MS' : 'Comic Sans MS',
+ 'Courier New' : 'Courier New',
+ 'Garamond' : 'Garamond',
+ 'Georgia' : 'Georgia',
+ 'Tahoma' : 'Tahoma',
+ 'Times New Roman' : 'Times New Roman',
+ 'Trebuchet MS' : 'Trebuchet MS',
+ 'Verdana' : 'Verdana'
+ },
+ 'lineheight.lineHeight' : [
+ {'1' : 'Line height 1'},
+ {'1.5' : 'Line height 1.5'},
+ {'2' : 'Line height 2'},
+ {'2.5' : 'Line height 2.5'},
+ {'3' : 'Line height 3'}
+ ],
+ 'template.selectTemplate' : 'Template',
+ 'template.replaceContent' : 'Replace current content',
+ 'template.fileList' : {
+ '1.html' : 'Image and Text',
+ '2.html' : 'Table',
+ '3.html' : 'List'
+ }
+}, 'en');
+
+//自动加载代码美化的js插件
+// KindEditor.loadScript(KindEditor.options.pluginsPath+"code/prettify.js");
+// KindEditor.each(KindEditor.options.items, function(i, name) {
+// if (name == 'code') {
+// KindEditor.options.items[i] = 'map';
+// }
+// });
+KindEditor.options.langType = 'en';
diff --git a/addons/nkeditor/assets/lang/ja-JP.js b/addons/nkeditor/assets/lang/ja-JP.js
new file mode 100644
index 0000000000000000000000000000000000000000..7806d089942b164a0b173cd9ce220774d4dd9dce
--- /dev/null
+++ b/addons/nkeditor/assets/lang/ja-JP.js
@@ -0,0 +1,234 @@
+/*******************************************************************************
+* @author 您的名字 お名前
+*******************************************************************************/
+
+KindEditor.lang({
+ source : 'HTMLコード',
+ preview : 'プレビュー',
+ undo : '戻る(Ctrl+Z)',
+ redo : '進む(Ctrl+Y)',
+ cut : 'カット(Ctrl+X)',
+ copy : 'コピー(Ctrl+C)',
+ paste : '貼り付け(Ctrl+V)',
+ plainpaste : 'フォーマットされていないテキストとして貼り付ける',
+ wordpaste : '「word」ドからペースト',
+ selectall : 'すべて選択(Ctrl+A)',
+ justifyleft : '左揃え',
+ justifycenter : '中央揃え',
+ justifyright : '右揃え',
+ justifyfull : '両端揃え',
+ insertorderedlist : '番号',
+ insertunorderedlist : '箇条書き',
+ indent : 'インデントを増やす',
+ outdent : 'インデントを減らす',
+ subscript : '下付き',
+ superscript : '上付き',
+ formatblock : '段落',
+ fontname : 'フォント',
+ fontsize : 'フォントサイズ',
+ forecolor : 'フォントカラー',
+ hilitecolor : 'テキストの背景',
+ bold : '太字(Ctrl+B)',
+ italic : '斜体(Ctrl+I)',
+ underline : '下線(Ctrl+U)',
+ strikethrough : '取り消し線',
+ removeformat : 'フォーマットを削除',
+ image : '画像',
+ multiimage : '一括画像アップロード',
+ flash : 'Flash',
+ media : 'ビデオとオーディオ',
+ table : 'テーブル',
+ tablecell : 'セル',
+ hr : '水平線を挿入する',
+ emoticons : '絵文字を挿入する',
+ link : 'ハイパーリンク',
+ unlink : 'ハイパーリンクをキャンセル',
+ fullscreen : 'フルスクリーン表示',
+ about : 'について',
+ print : 'プリント(Ctrl+P)',
+ filemanager : 'ファイルスペース',
+ code : 'プログラムコードを挿入',
+ map : 'Googleマップ',
+ baidumap : 'Baiduマップ',
+ lineheight : '行間隔',
+ clearhtml : 'HTMLコードをクリア',
+ pagebreak : 'ページ区切りの挿入',
+ quickformat : 'ワンクリックレイアウト',
+ insertfile : 'ファイルの挿入',
+ template : 'テンプレートの挿入',
+ anchor : 'アンカー',
+ yes : 'はい',
+ no : 'いいえ',
+ close : '閉じる',
+ editImage : 'イメージプロパティ',
+ deleteImage : 'イメージを削除',
+ editFlash : 'Flashプロパティ',
+ deleteFlash : 'Flashを削除',
+ editMedia : 'ビデオとオーディオのプロパティ',
+ deleteMedia : 'ビデオとオーディオを削除',
+ editLink : 'ハイパーリンク属性',
+ deleteLink : 'ハイパーリンクを削除',
+ editAnchor : 'アンカー属性',
+ deleteAnchor : 'アンカーを削除',
+ tableprop : 'テーブル属性',
+ tablecellprop : 'セル属性',
+ tableinsert : 'テーブルを挿入',
+ tabledelete : 'テーブルを削除',
+ tablecolinsertleft : '左に列を挿入する',
+ tablecolinsertright : '右に列を挿入する',
+ tablerowinsertabove : '上に行を挿入する',
+ tablerowinsertbelow : '下に行を挿入する',
+ tablerowmerge : '下にセルをマージする',
+ tablecolmerge : '右にセルをマージする',
+ tablerowsplit : '行を分割',
+ tablecolsplit : '列を分割',
+ tablecoldelete : '列を削除',
+ tablerowdelete : '行を削除',
+ noColor : '色なし',
+ pleaseSelectFile : 'ファイルを選択してください。',
+ invalidImg : "有効なURLアドレスを入力してください。\ n jpg、gif、bmp、png形式のみが許可されています。",
+ invalidMedia : "有効なURLアドレスを入力してください。swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb形式のみが許可されています。",
+ invalidWidth : "幅は数字でなければなりません。",
+ invalidHeight : "高さは数字でなければなりません。",
+ invalidBorder : "ボーダーは数字でなければなりません。",
+ invalidUrl : "有効なURLアドレスを入力してください。",
+ invalidRows : '行数は必須項目で、0以上の数字を入力してください。',
+ invalidCols : '列数は必須項目で、0以上の数字を入力してください。',
+ invalidPadding : 'マージンは数字でなければなりません。',
+ invalidSpacing : 'スペースは数字でなければなりません。',
+ invalidJson : 'サーバーエラー。',
+ uploadSuccess : 'アップロード成功。',
+ cutError : 'ブラウザのセキュリティ設定によってカット操作を使用できないので、ショートカットキー(Ctrl + X)を使用してください。',
+ copyError : 'ブラウザのセキュリティ設定によってコピー操作をできないので、ショートカットキー(Ctrl + C)を使用してください。',
+ pasteError : 'ブラウザのセキュリティ設定によって貼り付け操作をできないので、ショートカットキー(Ctrl + V)を使用してください。',
+ ajaxLoading : '読み込み中、お待ちください...',
+ uploadLoading : 'アップロード、しばらくお待ちください...',
+ uploadError : 'アップロードエラー',
+ 'plainpaste.comment' : 'ショートカットキー(Ctrl + V)でコンテンツを下のボックスに貼り付けてください。',
+ 'wordpaste.comment' : 'ショートカットキー(Ctrl + V)でコンテンツを下のボックスに貼り付けてください。',
+ 'code.pleaseInput' : 'プログラムコードを入力してください。 ',
+ 'link.url' : 'URL',
+ 'link.linkType' : 'タイプを開く',
+ 'link.newWindow' : '新しいウィンドウ',
+ 'link.selfWindow' : '現在のウィンドウ',
+ 'flash.url' : 'URL',
+ 'flash.width' : '幅',
+ 'flash.height' : '高さ',
+ 'flash.upload' : 'アップロード',
+ 'flash.viewServer' : 'ファイルスペース',
+ 'media.url' : 'URL',
+ 'media.width' : '幅',
+ 'media.height' : '高さ',
+ 'media.autostart' : '自動再生',
+ 'media.upload' : 'アップロード',
+ 'media.viewServer' : 'ファイルスペース',
+ 'image.remoteImage' : 'ネットワークイメージ',
+ 'image.localImage' : 'ローカルアップロード',
+ 'image.remoteUrl' : 'イメージアドレス ',
+ 'image.localUrl' : 'アップロードファイル',
+ 'image.size' : 'イメージサイズ',
+ 'image.width' : '幅',
+ 'image.height' : '高さ',
+ 'image.resetSize' : 'リセットサイズ',
+ 'image.align' : '配置',
+ 'image.defaultAlign' : 'デフォルト',
+ 'image.leftAlign' : '左揃え',
+ 'image.rightAlign' : '右揃え',
+ 'image.imgTitle' : '画像の説明',
+ 'image.upload' : 'ブラウズ...',
+ 'image.viewServer' : 'イメージスペース',
+ 'multiimage.uploadDesc' : 'ユーザーが<%= uploadLimit%>画像を同時にアップロードできますが、画像の容量は<%= sizeLimit%>を超えることができません',
+ 'multiimage.startUpload' : 'アップロード',
+ 'multiimage.clearAll' : 'すべてクリア',
+ 'multiimage.insertAll' : 'すべて挿入',
+ 'multiimage.queueLimitExceeded' : 'ファイルの数が上限を超えています。',
+ 'multiimage.fileExceedsSizeLimit' : 'ファイルサイズが制限を超えています。',
+ 'multiimage.zeroByteFile' : '空のファイルをアップロードできません。 ',
+ 'multiimage.invalidFiletype' : 'ファイル形式は正しくありません。',
+ 'multiimage.unknownError' : 'エラー、アップロードできません。',
+ 'multiimage.pending' : 'アップロード待ち',
+ 'multiimage.uploadError' : 'アップロード失敗',
+ 'filemanager.emptyFolder' : '空のフォルダ',
+ 'filemanager.moveup' : '前のフォルダに移動',
+ 'filemanager.viewType' : '表示モード:',
+ 'filemanager.viewImage' : 'サムネイル',
+ 'filemanager.listImage' : '詳細',
+ 'filemanager.orderType' : '並べ替え:',
+ 'filemanager.fileName' : 'ネーム',
+ 'filemanager.fileSize' : 'サイズ',
+ 'filemanager.fileType' : 'タイプ',
+ 'insertfile.url' : 'URL',
+ 'insertfile.title' : 'ファイルの説明',
+ 'insertfile.upload' : 'アップロード',
+ 'insertfile.viewServer' : 'ファイルスペース',
+ 'table.cells' : 'セル番号',
+ 'table.rows' : '行数',
+ 'table.cols' : '列数',
+ 'table.size' : 'サイズ',
+ 'table.width' : '幅',
+ 'table.height' : '高さ',
+ 'table.percent' : '%',
+ 'table.px' : 'px',
+ 'table.space' : 'テーブルスペース',
+ 'table.padding' : 'パッディング',
+ 'table.spacing' : 'スペース',
+ 'table.align' : '配置',
+ 'table.textAlign' : '水平配置',
+ 'table.verticalAlign' : '垂直配置',
+ 'table.alignDefault' : 'デフォルト',
+ 'table.alignLeft' : '左揃え',
+ 'table.alignCenter' : '中央揃え',
+ 'table.alignRight' : '右揃え',
+ 'table.alignTop' : 'トップ',
+ 'table.alignMiddle' : 'ミドル',
+ 'table.alignBottom' : 'ボトム',
+ 'table.alignBaseline' : 'ベースライン',
+ 'table.border' : 'ボーダー',
+ 'table.borderWidth' : 'ボーダー',
+ 'table.borderColor' : 'カラー',
+ 'table.backgroundColor' : '背景色',
+ 'map.address' : 'アドレス: ',
+ 'map.search' : '検索',
+ 'baidumap.address' : 'アドレス: ',
+ 'baidumap.search' : '検索',
+ 'baidumap.insertDynamicMap' : 'ダイナミックマップの挿入',
+ 'anchor.name' : 'アンカー名',
+
+ 'formatblock.formatBlock' : {
+ h1 : '見出し1',
+ h2 : '見出し2',
+ h3 : '見出し3',
+ h4 : '見出し4',
+ p : '正 文'
+ },
+ 'fontname.fontName' : {
+ 'SimSun' : '明朝体',
+ 'NSimSun' : '新宋体',
+ 'FangSong_GB2312' : '仿宋_GB2312',
+ 'KaiTi_GB2312' : '楷書体_GB2312',
+ 'SimHei' : 'ゴチック体',
+ 'Microsoft YaHei' : 'Msyh',
+ 'Arial' : 'Arial',
+ 'Arial Black' : 'Arial Black',
+ 'Times New Roman' : 'Times New Roman',
+ 'Courier New' : 'Courier New',
+ 'Tahoma' : 'Tahoma',
+ 'Verdana' : 'Verdana'
+ },
+ 'lineheight.lineHeight' : [
+ {'1' : '行間1倍'},
+ {'1.5' : '行間1.5倍'},
+ {'2' : '行間2倍'},
+ {'2.5' : '行間2.5倍'},
+ {'3' : '行間3倍'}
+ ],
+ 'template.selectTemplate' : 'オプションテンプレート',
+ 'template.replaceContent' : '現在のコンテンツを置き換える',
+ 'template.fileList' : {
+ '1.html' : 'イメージとテキスト',
+ '2.html' : '表',
+ '3.html' : '段落番号'
+ }
+}, 'ja-JP');
+
+KindEditor.options.langType = 'ja-JP';
\ No newline at end of file
diff --git a/addons/nkeditor/assets/lang/ko.js b/addons/nkeditor/assets/lang/ko.js
new file mode 100644
index 0000000000000000000000000000000000000000..bf5eb2255bc8417193da34d007476c4e78efba95
--- /dev/null
+++ b/addons/nkeditor/assets/lang/ko.js
@@ -0,0 +1,246 @@
+/*******************************************************************************
+* KindEditor - WYSIWYG HTML Editor for Internet
+* Copyright (C) 2006-2011 kindsoft.net
+*
+* @author Composite
+* @site http://www.kindsoft.net/
+* @licence http://www.kindsoft.net/license.php
+*******************************************************************************/
+
+KindEditor.lang({
+ source : '소스',
+ preview : '미리보기',
+ undo : '작업취소(Ctrl+Z)',
+ redo : '작업재개(Ctrl+Y)',
+ cut : '잘라내기(Ctrl+X)',
+ copy : '복사(Ctrl+C)',
+ paste : '붙여넣기(Ctrl+V)',
+ plainpaste : '일반 텍스트로 붙여넣기',
+ wordpaste : '워드 문서로 붙여넣기',
+ selectall : '전체 선택',
+ justifyleft : '왼쪽 정렬',
+ justifycenter : '가운데 정렬',
+ justifyright : '오른쪽 정렬',
+ justifyfull : '양쪽 정렬',
+ insertorderedlist : '순서 목록',
+ insertunorderedlist : '비순서 목록',
+ indent : '들여쓰기',
+ outdent : '내어쓰기',
+ subscript : '아랫첨자',
+ superscript : '윗첨자',
+ formatblock : '문단 형식',
+ fontname : '글꼴',
+ fontsize : '글자 크기',
+ forecolor : '글자색',
+ hilitecolor : '강조색',
+ bold : '굵게(Ctrl+B)',
+ italic : '이텔릭(Ctrl+I)',
+ underline : '빝줄(Ctrl+U)',
+ strikethrough : '취소선',
+ removeformat : '형식 제거',
+ image : '이미지 추가',
+ multiimage : '여러 이미지 추가',
+ flash : '플래시 추가',
+ media : '미디어 추가',
+ table : '표',
+ tablecell : '열',
+ hr : '구분선 추가',
+ emoticons : '이모티콘 추가',
+ link : '링크',
+ unlink : '링크 제거',
+ fullscreen : '전체 화면 모드',
+ about : '이 에디터는...',
+ print : '인쇄',
+ filemanager : '파일 관리자',
+ code : '코드 추가',
+ map : '구글 맵 추가',
+ baidumap : '바이두 맵 추가',
+ lineheight : '행 간격',
+ clearhtml : 'HTML 코드 정리',
+ pagebreak : '페이지 구분 추가',
+ quickformat : '빠른 형식',
+ insertfile : '파일 추가',
+ template : '템플릿 추가',
+ anchor : '책갈피',
+ yes : '확인',
+ no : '취소',
+ close : '닫기',
+ editImage : '이미지 속성',
+ deleteImage : '이미지 삭제',
+ editFlash : '플래시 속성',
+ deleteFlash : '플래시 삭제',
+ editMedia : '미디어 속성',
+ deleteMedia : '미디어 삭제',
+ editLink : '링크 속성',
+ deleteLink : '링크 삭제',
+ editAnchor : 'Anchor properties',
+ deleteAnchor : 'Delete Anchor',
+ tableprop : '표 속성',
+ tablecellprop : '열 속성',
+ tableinsert : '표 추가',
+ tabledelete : '표 삭제',
+ tablecolinsertleft : '왼쪽으로 열 추가',
+ tablecolinsertright : '오른쪽으로 열 추가',
+ tablerowinsertabove : '위쪽으로 열 추가',
+ tablerowinsertbelow : '아래쪽으로 열 추가',
+ tablerowmerge : '아래로 병합',
+ tablecolmerge : '오른쪽으로 병합',
+ tablerowsplit : '행 나누기',
+ tablecolsplit : '열 나누기',
+ tablecoldelete : '열 삭제',
+ tablerowdelete : '행 삭제',
+ noColor : '기본색',
+ pleaseSelectFile : '파일 선택',
+ invalidImg : "올바른 주소를 입력하세요.\njpg,gif,bmp,png 형식이 가능합니다.",
+ invalidMedia : "올바른 주소를 입력하세요.\nswf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb 형식이 가능합니다.",
+ invalidWidth : "넓이 값은 숫자여야 합니다.",
+ invalidHeight : "높이 값은 숫자여야 합니다.",
+ invalidBorder : "굵기 값은 숫자여야 합니다.",
+ invalidUrl : "올바른 주소를 입력하세요.",
+ invalidRows : '올바른 행이 아닙니다.',
+ invalidCols : '올바른 열이 아닙니다.',
+ invalidPadding : '안쪽 여백 값은 숫자여야 합니다.',
+ invalidSpacing : '간격 길이 값은 숫자여야 합니다.',
+ invalidJson : '올바른 JSON 형식이 아닙니다.',
+ uploadSuccess : '업로드가 완료되었습니다.',
+ cutError : '브라우저가 잘라내기 기능을 지원하지 않습니다, 단축키로 대신 사용하세요. (Ctrl+X)',
+ copyError : '브라우저가 복사 기능을 지원하지 않습니다, 단축키로 대신 사용하세요. (Ctrl+X)',
+ pasteError : '브라우저가 붙여넣기 기능을 지원하지 않습니다, 단축키로 대신 사용하세요. (Ctrl+X)',
+ ajaxLoading : '불러오는 중 ...',
+ uploadLoading : '업로드 중 ...',
+ uploadError : '업로드 오류',
+ 'plainpaste.comment' : '단축키(Ctrl+V)를 통하여 여기에 텍스트를 붙여넣으세요.',
+ 'wordpaste.comment' : '단축키(Ctrl+V)를 통하여 여기에 워드 텍스트를 붙여넣으세요.',
+ 'code.pleaseInput' : 'Please input code.',
+ 'link.url' : '주소',
+ 'link.linkType' : '창',
+ 'link.newWindow' : '새 창',
+ 'link.selfWindow' : '현재 창',
+ 'flash.url' : '주소',
+ 'flash.width' : '넓이',
+ 'flash.height' : '높이',
+ 'flash.upload' : '업로드',
+ 'flash.viewServer' : '찾아보기',
+ 'media.url' : '주소',
+ 'media.width' : '넓이',
+ 'media.height' : '높이',
+ 'media.autostart' : '자동 시작',
+ 'media.upload' : '업로드',
+ 'media.viewServer' : '찾아보기',
+ 'image.remoteImage' : '외부 이미지',
+ 'image.localImage' : '내부 이미지',
+ 'image.remoteUrl' : '주소',
+ 'image.localUrl' : '파일',
+ 'image.size' : '크기',
+ 'image.width' : '넓이',
+ 'image.height' : '높이',
+ 'image.resetSize' : '기본 크기로',
+ 'image.align' : '정렬',
+ 'image.defaultAlign' : '기본',
+ 'image.leftAlign' : '왼쪽',
+ 'image.rightAlign' : '오른쪽',
+ 'image.imgTitle' : '제목',
+ 'image.upload' : '찾아보기',
+ 'image.viewServer' : '찾아보기',
+ 'multiimage.uploadDesc' : '최대 이미지 개수: <%=uploadLimit%>개, 개당 이미지 크기: <%=sizeLimit%>',
+ 'multiimage.startUpload' : '업로드 시작',
+ 'multiimage.clearAll' : '모두 삭제',
+ 'multiimage.insertAll' : '모두 삽입',
+ 'multiimage.queueLimitExceeded' : '업로드 개수가 초과되었습니다.',
+ 'multiimage.fileExceedsSizeLimit' : '업로드 크기가 초과되었습니다.',
+ 'multiimage.zeroByteFile' : '파일 크기가 없습니다.',
+ 'multiimage.invalidFiletype' : '올바른 이미지가 아닙니다.',
+ 'multiimage.unknownError' : '알 수 없는 업로드 오류가 발생하였습니다.',
+ 'multiimage.pending' : '처리 중 ...',
+ 'multiimage.uploadError' : '업로드 오류',
+ 'filemanager.emptyFolder' : '빈 폴더',
+ 'filemanager.moveup' : '위로',
+ 'filemanager.viewType' : '보기 방식: ',
+ 'filemanager.viewImage' : '미리 보기',
+ 'filemanager.listImage' : '목록',
+ 'filemanager.orderType' : '정렬 방식: ',
+ 'filemanager.fileName' : '이름별',
+ 'filemanager.fileSize' : '크기별',
+ 'filemanager.fileType' : '종류별',
+ 'insertfile.url' : '주소',
+ 'insertfile.title' : '제목',
+ 'insertfile.upload' : '업로드',
+ 'insertfile.viewServer' : '찾아보기',
+ 'table.cells' : '열',
+ 'table.rows' : '행',
+ 'table.cols' : '열',
+ 'table.size' : '표 크기',
+ 'table.width' : '넓이',
+ 'table.height' : '높이',
+ 'table.percent' : '%',
+ 'table.px' : 'px',
+ 'table.space' : '간격',
+ 'table.padding' : '안쪽여백',
+ 'table.spacing' : '간격',
+ 'table.align' : '정렬',
+ 'table.textAlign' : '수직',
+ 'table.verticalAlign' : '수평',
+ 'table.alignDefault' : '기본',
+ 'table.alignLeft' : '왼쪽',
+ 'table.alignCenter' : '가운데',
+ 'table.alignRight' : '오른쪽',
+ 'table.alignTop' : '위쪽',
+ 'table.alignMiddle' : '중간',
+ 'table.alignBottom' : '아래쪽',
+ 'table.alignBaseline' : '글자기준',
+ 'table.border' : '테두리',
+ 'table.borderWidth' : '크기',
+ 'table.borderColor' : '색상',
+ 'table.backgroundColor' : '배경',
+ 'map.address' : '주소: ',
+ 'map.search' : '검색',
+ 'baidumap.address' : '주소: ',
+ 'baidumap.search' : '검색',
+ 'baidumap.insertDynamicMap' : '동적 지도',
+ 'anchor.name' : '책갈피명',
+ 'formatblock.formatBlock' : {
+ h1 : '제목 1',
+ h2 : '제목 2',
+ h3 : '제목 3',
+ h4 : '제목 4',
+ p : '본문'
+ },
+ 'fontname.fontName' : {
+ 'Gulim' : '굴림',
+ 'Dotum' : '돋움',
+ 'Batang' : '바탕',
+ 'Gungsuh' : '궁서',
+ 'Malgun Gothic' : '맑은 고딕',
+ 'Arial' : 'Arial',
+ 'Arial Black' : 'Arial Black',
+ 'Comic Sans MS' : 'Comic Sans MS',
+ 'Courier New' : 'Courier New',
+ 'Garamond' : 'Garamond',
+ 'Georgia' : 'Georgia',
+ 'Tahoma' : 'Tahoma',
+ 'Times New Roman' : 'Times New Roman',
+ 'Trebuchet MS' : 'Trebuchet MS',
+ 'Verdana' : 'Verdana'
+ },
+ 'lineheight.lineHeight' : [
+ {'1' : '행간 1'},
+ {'1.5' : '행간 1.5'},
+ {'2' : '행간 2'},
+ {'2.5' : '행간 2.5'},
+ {'3' : '행간 3'}
+ ],
+ 'template.selectTemplate' : '템플릿',
+ 'template.replaceContent' : '내용 바꾸기',
+ 'template.fileList' : {
+ '1.html' : '이미지와 텍스트',
+ '2.html' : '표',
+ '3.html' : '목록'
+ }
+}, 'ko');
+
+KindEditor.each(KindEditor.options.items, function(i, name) {
+ if (name == 'baidumap') {
+ KindEditor.options.items[i] = 'map';
+ }
+});
+KindEditor.options.langType = 'ko';
diff --git a/addons/nkeditor/assets/lang/ru.js b/addons/nkeditor/assets/lang/ru.js
new file mode 100644
index 0000000000000000000000000000000000000000..dda10bf3a96f0eecdc344eb9c4f230d574db864b
--- /dev/null
+++ b/addons/nkeditor/assets/lang/ru.js
@@ -0,0 +1,242 @@
+/*******************************************************************************
+* KindEditor - WYSIWYG HTML Editor for Internet
+* Copyright (C) 2006-2011 kindsoft.net
+*
+* @author Roddy
+* @site http://www.kindsoft.net/
+* @licence http://www.kindsoft.net/license.php
+* Translated to Russian by Valery Votintsev (http://codersclub.org/)
+*******************************************************************************/
+
+KindEditor.lang({
+ source : 'Source',
+ preview : 'Preview',
+ undo : 'Отмена(Ctrl+Z)',
+ redo : 'Повтор(Ctrl+Y)',
+ cut : 'Вырезать(Ctrl+X)',
+ copy : 'Копировать(Ctrl+C)',
+ paste : 'Вставить(Ctrl+V)',
+ plainpaste : 'Вставить как простой текст',
+ wordpaste : 'Вставить из Word',
+ selectall : 'Выбрать все',
+ justifyleft : 'Выравнивание влево',
+ justifycenter : 'Выравнивание по центру',
+ justifyright : 'Выравнивание вправо',
+ justifyfull : 'Выравнивание по обеим сторонам',
+ insertorderedlist : 'Нумерованый список',
+ insertunorderedlist : 'Ненумерованый список',
+ indent : 'Добавить отступ',
+ outdent : 'Убрать отступ',
+ subscript : 'Надстрочный',
+ superscript : 'Подстрочный',
+ formatblock : 'Формат параграфа',
+ fontname : 'Шрифт',
+ fontsize : 'Размер',
+ forecolor : 'Цвет текста',
+ hilitecolor : 'Цвет фона',
+ bold : 'Жирный(Ctrl+B)',
+ italic : 'Наклонный(Ctrl+I)',
+ underline : 'Подчёркнутый(Ctrl+U)',
+ strikethrough : 'Перечёркнутый',
+ removeformat : 'Удалить формат',
+ image : 'Изображение',
+ multiimage : 'Мульти-загрузка',
+ flash : 'Flash',
+ media : 'Встроенные данные',
+ table : 'Таблица',
+ tablecell : 'Ячейка',
+ hr : 'Горизонтальный разделитель',
+ emoticons : 'Смайл',
+ link : 'Ссылка',
+ unlink : 'Убрать ссылку',
+ fullscreen : 'На весь экран',
+ about : 'О программе',
+ print : 'Печать',
+ filemanager : 'Файлы',
+ code : 'Код',
+ map : 'Карта Google',
+ baidumap : 'Карта Baidu',
+ lineheight : 'Межстрочный интервал',
+ clearhtml : 'Очистить HTML код',
+ pagebreak : 'Разрыв страницы',
+ quickformat : 'Быстрый формат',
+ insertfile : 'Вставить файл',
+ template : 'Вставить шаблон',
+ anchor : 'Якорь',
+ yes : 'OK',
+ no : 'Отмена',
+ close : 'Закрыть',
+ editImage : 'Свойства изображения',
+ deleteImage : 'Удалить изображение',
+ editFlash : 'Свойства Flash',
+ deleteFlash : 'Удалить Flash',
+ editMedia : 'Свойства Media',
+ deleteMedia : 'Удалить Media',
+ editLink : 'Свойства ссылки',
+ deleteLink : 'Удалить ссылку',
+ editAnchor : 'Anchor properties',
+ deleteAnchor : 'Delete Anchor',
+ tableprop : 'Свойства таблицы',
+ tablecellprop : 'Свойства ячейки',
+ tableinsert : 'Вставить таблицу',
+ tabledelete : 'Удалить таблицу',
+ tablecolinsertleft : 'Добавить столбец слева',
+ tablecolinsertright : 'Добавить столбец справа',
+ tablerowinsertabove : 'Добавить строку выше',
+ tablerowinsertbelow : 'Добавить строку ниже',
+ tablerowmerge : 'Объединить вниз',
+ tablecolmerge : 'Объединить вправо',
+ tablerowsplit : 'Разделить строку',
+ tablecolsplit : 'Разделить столбец',
+ tablecoldelete : 'Удалить столбец',
+ tablerowdelete : 'Удалить строку',
+ noColor : 'По умолчанию',
+ pleaseSelectFile : 'Выберите файл.',
+ invalidImg : "Укажите корректный URL изображения.\nРазрешённые форматы: jpg,gif,bmp,png",
+ invalidMedia : "Укажите корректный тип медиа-объекта.\nРазрешённые типы: swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb",
+ invalidWidth : "Ширина должна быть числом.",
+ invalidHeight : "Высота должна быть числом.",
+ invalidBorder : "Ширина рамки должна быть числом.",
+ invalidUrl : "Укажите корректный URL.",
+ invalidRows : 'Неверные строки.',
+ invalidCols : 'Неверные столбцы.',
+ invalidPadding : 'padding должен быть числом.',
+ invalidSpacing : 'spacing должен быть числом.',
+ invalidJson : 'Неверная JSON строка.',
+ uploadSuccess : 'Загрузка завершена.',
+ cutError : 'Данная опция не поддерживается вашим браузером, воспользуйтесь комбинацией клавиш (Ctrl+X).',
+ copyError : 'Данная опция не поддерживается вашим браузером, воспользуйтесь комбинацией клавиш (Ctrl+C).',
+ pasteError : 'Данная опция не поддерживается вашим браузером, воспользуйтесь комбинацией клавиш (Ctrl+V).',
+ ajaxLoading : 'Загрузка ...',
+ uploadLoading : 'Загрузка ...',
+ uploadError : 'Сбой загрузки',
+ 'plainpaste.comment' : 'Для вставки скопированного текста воспользуйтесь комбинацией клавиш (Ctrl+V).',
+ 'wordpaste.comment' : 'Для вставки скопированного текста воспользуйтесь комбинацией клавиш (Ctrl+V).',
+ 'code.pleaseInput' : 'Введите код.',
+ 'link.url' : 'URL',
+ 'link.linkType' : 'Открывать ссылку',
+ 'link.newWindow' : 'в новом окне',
+ 'link.selfWindow' : 'в том же окне',
+ 'flash.url' : 'URL',
+ 'flash.width' : 'Ширина',
+ 'flash.height' : 'Высота',
+ 'flash.upload' : 'Загрузить',
+ 'flash.viewServer' : 'Выбрать',
+ 'media.url' : 'URL',
+ 'media.width' : 'Ширина',
+ 'media.height' : 'Высота',
+ 'media.autostart' : 'Автостарт',
+ 'media.upload' : 'Загрузить',
+ 'media.viewServer' : 'Выбрать',
+ 'image.remoteImage' : 'Вставить URL изображения',
+ 'image.localImage' : 'Загрузить',
+ 'image.remoteUrl' : 'URL',
+ 'image.localUrl' : 'Файл',
+ 'image.size' : 'Размер',
+ 'image.width' : 'Ширина',
+ 'image.height' : 'Высота',
+ 'image.resetSize' : 'Сбросить размеры',
+ 'image.align' : 'Выравнивание',
+ 'image.defaultAlign' : 'По умолчанию',
+ 'image.leftAlign' : 'Влево',
+ 'image.rightAlign' : 'Вправо',
+ 'image.imgTitle' : 'Название',
+ 'image.upload' : 'Загрузить',
+ 'image.viewServer' : 'Выбрать',
+ 'multiimage.uploadDesc' : 'Максимальное кол-во изображений: <%=uploadLimit%>, Максимальный размер одного изображения: <%=sizeLimit%>',
+ 'multiimage.startUpload' : 'Начать загрузку',
+ 'multiimage.clearAll' : 'Очистить все',
+ 'multiimage.insertAll' : 'Вставить все',
+ 'multiimage.queueLimitExceeded' : 'Превышен лимит очереди.',
+ 'multiimage.fileExceedsSizeLimit' : 'Превышен максимальный размер файла.',
+ 'multiimage.zeroByteFile' : 'Файл нулевой длины.',
+ 'multiimage.invalidFiletype' : 'Недопустимый тип файла.',
+ 'multiimage.unknownError' : 'Непредвиденная ошибка загрузки.',
+ 'multiimage.pending' : 'Ожидает ...',
+ 'multiimage.uploadError' : 'Ошибка загрузки',
+ 'filemanager.emptyFolder' : 'Папка пуста',
+ 'filemanager.moveup' : 'Наверх',
+ 'filemanager.viewType' : 'Тип показа: ',
+ 'filemanager.viewImage' : 'Превьюшки',
+ 'filemanager.listImage' : 'Список',
+ 'filemanager.orderType' : 'Сортировка: ',
+ 'filemanager.fileName' : 'По имени',
+ 'filemanager.fileSize' : 'По размеру',
+ 'filemanager.fileType' : 'По типу',
+ 'insertfile.url' : 'URL',
+ 'insertfile.title' : 'Название',
+ 'insertfile.upload' : 'Загрузить',
+ 'insertfile.viewServer' : 'Выбрать',
+ 'table.cells' : 'Ячейки',
+ 'table.rows' : 'Строки',
+ 'table.cols' : 'Столбцы',
+ 'table.size' : 'Размеры',
+ 'table.width' : 'Ширина',
+ 'table.height' : 'Высота',
+ 'table.percent' : '%',
+ 'table.px' : 'px',
+ 'table.space' : 'Space',
+ 'table.padding' : 'Padding',
+ 'table.spacing' : 'Spacing',
+ 'table.align' : 'Выравнивание',
+ 'table.textAlign' : 'По горизонтали',
+ 'table.verticalAlign' : 'По вертикали',
+ 'table.alignDefault' : 'По умолчанию',
+ 'table.alignLeft' : 'Влево',
+ 'table.alignCenter' : 'По центру',
+ 'table.alignRight' : 'Вправо',
+ 'table.alignTop' : 'Вверх',
+ 'table.alignMiddle' : 'Посередине',
+ 'table.alignBottom' : 'Вниз',
+ 'table.alignBaseline' : 'По базовой линии',
+ 'table.border' : 'Рамка',
+ 'table.borderWidth' : 'Ширина',
+ 'table.borderColor' : 'Цвет',
+ 'table.backgroundColor' : 'Цвет фона',
+ 'map.address' : 'Адрес: ',
+ 'map.search' : 'Поиск',
+ 'baidumap.address' : 'Адрес: ',
+ 'baidumap.search' : 'Поиск',
+ 'baidumap.insertDynamicMap' : 'Динамическая карта',
+ 'anchor.name' : 'Имя якоря',
+ 'formatblock.formatBlock' : {
+ h1 : 'Заголовок 1',
+ h2 : 'Заголовок 2',
+ h3 : 'Заголовок 3',
+ h4 : 'Заголовок 4',
+ p : 'Обычный текст'
+ },
+ 'fontname.fontName' : {
+ 'Arial' : 'Arial',
+ 'Arial Black' : 'Arial Black',
+ 'Comic Sans MS' : 'Comic Sans MS',
+ 'Courier New' : 'Courier New',
+ 'Garamond' : 'Garamond',
+ 'Georgia' : 'Georgia',
+ 'Tahoma' : 'Tahoma',
+ 'Times New Roman' : 'Times New Roman',
+ 'Trebuchet MS' : 'Trebuchet MS',
+ 'Verdana' : 'Verdana'
+ },
+ 'lineheight.lineHeight' : [
+ {'1' : '1'},
+ {'1.5' : '1.5'},
+ {'2' : '2'},
+ {'2.5' : '2.5'},
+ {'3' : '3'}
+ ],
+ 'template.selectTemplate' : 'Шаблон',
+ 'template.replaceContent' : 'Заменить текущий шаблон',
+ 'template.fileList' : {
+ '1.html' : 'Текст и изображения',
+ '2.html' : 'Таблица',
+ '3.html' : 'Список'
+ }
+}, 'en');
+
+KindEditor.each(KindEditor.options.items, function(i, name) {
+ if (name == 'baidumap') {
+ KindEditor.options.items[i] = 'map';
+ }
+});
+KindEditor.options.langType = 'ru';
diff --git a/addons/nkeditor/assets/lang/zh-CN.js b/addons/nkeditor/assets/lang/zh-CN.js
new file mode 100644
index 0000000000000000000000000000000000000000..405e2f44425be5bae48a2a553bd7eecbbe6a8083
--- /dev/null
+++ b/addons/nkeditor/assets/lang/zh-CN.js
@@ -0,0 +1,267 @@
+/*******************************************************************************
+* KindEditor - WYSIWYG HTML Editor for Internet
+* Copyright (C) 2006-2011 kindsoft.net
+*
+* @author Roddy
+* @site http://www.kindsoft.net/
+* @licence http://www.kindsoft.net/license.php
+*******************************************************************************/
+
+KindEditor.lang({
+ source : 'HTML代码',
+ preview : '预览',
+ undo : '后退(Ctrl+Z)',
+ redo : '前进(Ctrl+Y)',
+ cut : '剪切(Ctrl+X)',
+ copy : '复制(Ctrl+C)',
+ paste : '粘贴(Ctrl+V)',
+ plainpaste : '粘贴为无格式文本',
+ wordpaste : '从Word粘贴',
+ selectall : '全选(Ctrl+A)',
+ justifyleft : '左对齐',
+ justifycenter : '居中',
+ justifyright : '右对齐',
+ justifyfull : '两端对齐',
+ insertorderedlist : '编号',
+ insertunorderedlist : '项目符号',
+ indent : '增加缩进',
+ outdent : '减少缩进',
+ subscript : '下标',
+ superscript : '上标',
+ formatblock : '段落',
+ fontname : '字体',
+ fontsize : '文字大小',
+ forecolor : '文字颜色',
+ hilitecolor : '文字背景',
+ bold : '粗体(Ctrl+B)',
+ italic : '斜体(Ctrl+I)',
+ underline : '下划线(Ctrl+U)',
+ strikethrough : '删除线',
+ removeformat : '删除格式',
+ image : '图片',
+ multiimage : '批量图片上传',
+ graft : '涂鸦',
+ flash : 'Flash',
+ media : '视音频',
+ table : '表格',
+ tablecell : '单元格',
+ hr : '插入横线',
+ emoticons : '插入表情',
+ link : '超级链接',
+ unlink : '取消超级链接',
+ fullscreen : '全屏显示',
+ about : '关于',
+ print : '打印(Ctrl+P)',
+ filemanager : '文件空间',
+ code : '插入程序代码',
+ quote : '插入引用',
+ map : 'Google地图',
+ baidumap : '百度地图',
+ lineheight : '行距',
+ clearhtml : '清理HTML代码',
+ pagebreak : '插入分页符',
+ quickformat : '一键排版',
+ insertfile : '插入文件',
+ template : '插入模板',
+ anchor : '锚点',
+ yes : '确定',
+ no : '取消',
+ close : '关闭',
+ editImage : '图片属性',
+ deleteImage : '删除图片',
+ editFlash : 'Flash属性',
+ deleteFlash : '删除Flash',
+ editMedia : '视音频属性',
+ deleteMedia : '删除视音频',
+ editLink : '超级链接属性',
+ deleteLink : '取消超级链接',
+ editAnchor : '锚点属性',
+ deleteAnchor : '删除锚点',
+ tableprop : '表格属性',
+ tablecellprop : '单元格属性',
+ tableinsert : '插入表格',
+ tabledelete : '删除表格',
+ tablecolinsertleft : '左侧插入列',
+ tablecolinsertright : '右侧插入列',
+ tablerowinsertabove : '上方插入行',
+ tablerowinsertbelow : '下方插入行',
+ tablerowmerge : '向下合并单元格',
+ tablecolmerge : '向右合并单元格',
+ tablerowsplit : '拆分行',
+ tablecolsplit : '拆分列',
+ tablecoldelete : '删除列',
+ tablerowdelete : '删除行',
+ noColor : '无颜色',
+ pleaseSelectFile : '请选择文件。',
+ invalidImg : "请输入有效的URL地址。\n只允许jpg,gif,bmp,png格式。",
+ invalidMedia : "请输入有效的URL地址。\n只允许swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb格式。",
+ invalidWidth : "宽度必须为数字。",
+ invalidHeight : "高度必须为数字。",
+ invalidBorder : "边框必须为数字。",
+ invalidUrl : "请输入有效的URL地址。",
+ invalidRows : '行数为必选项,只允许输入大于0的数字。',
+ invalidCols : '列数为必选项,只允许输入大于0的数字。',
+ invalidPadding : '边距必须为数字。',
+ invalidSpacing : '间距必须为数字。',
+ invalidJson : '服务器发生故障。',
+ uploadSuccess : '上传成功。',
+ cutError : '您的浏览器安全设置不允许使用剪切操作,请使用快捷键(Ctrl+X)来完成。',
+ copyError : '您的浏览器安全设置不允许使用复制操作,请使用快捷键(Ctrl+C)来完成。',
+ pasteError : '您的浏览器安全设置不允许使用粘贴操作,请使用快捷键(Ctrl+V)来完成。',
+ ajaxLoading : '加载中,请稍候 ...',
+ uploadLoading : '上传中,请稍候 ...',
+ uploadError : '上传错误',
+
+ 'plainpaste.comment' : '请使用快捷键(Ctrl+V)把内容粘贴到下面的方框里。',
+ 'wordpaste.comment' : '请使用快捷键(Ctrl+V)把内容粘贴到下面的方框里。',
+ 'code.pleaseInput' : '请输入程序代码。',
+ 'link.url' : 'URL',
+ 'link.linkType' : '打开类型',
+ 'link.newWindow' : '新窗口',
+ 'link.selfWindow' : '当前窗口',
+ 'flash.url' : 'URL',
+ 'flash.width' : '宽度',
+ 'flash.height' : '高度',
+ 'flash.upload' : '上传',
+ 'flash.viewServer' : '文件空间',
+ 'media.url' : 'URL',
+ 'media.width' : '宽度',
+ 'media.height' : '高度',
+ 'media.autostart' : '自动播放',
+ 'media.upload' : '上传',
+ 'media.viewServer' : '文件空间',
+ 'image.remoteImage' : '网络图片',
+ 'image.localImage' : '本地上传',
+ 'image.remoteUrl' : '图片地址',
+ 'image.localUrl' : '上传文件',
+ 'image.size' : '图片大小',
+ 'image.width' : '宽',
+ 'image.height' : '高',
+ 'image.resetSize' : '重置大小',
+ 'image.align' : '对齐方式',
+ 'image.defaultAlign' : '默认方式',
+ 'image.leftAlign' : '左对齐',
+ 'image.rightAlign' : '右对齐',
+ 'image.imgTitle' : '图片说明',
+ 'image.upload' : '浏览...',
+ 'image.viewServer' : '图片空间',
+
+ 'multiimage.title' : '多图上传',
+ 'multiimage.uploadDesc' : '共选择了 <%=numSelect%> 张图片,共 <%=totalSize%>, 还可以添加 <%=numLeft%> 张图片.',
+ 'multiimage.startUpload' : '开始上传',
+ 'multiimage.noListUrl' : '无法获取图片,请先配置 fileManagerJson.',
+ 'multiimage.noSearchUrl' : '无法进行图片搜索,请先配置 imageSearchJson.',
+ 'multiimage.noDataText' : '(⊙o⊙)亲,没有多数据了。',
+ 'multiimage.closeText' : '关闭对话框',
+ 'multiimage.confirmBtnText' : '确定',
+ 'multiimage.cancelBtnText' : '取消',
+ 'multiimage.loadMoreData' : '往下拉动滚动条可以加载更多数据.',
+ 'multiimage.depJQueryError' : '文件管理插件依赖 jQuery, 请先引入 jQuery.',
+ 'multiimage.localUpload' : '本地上传',
+ 'multiimage.fileServer' : '文件服务器',
+ 'multiimage.imgSearch' : '图片搜索',
+ 'multiimage.selectFile' : '点击选择图片',
+ 'multiimage.continueAdd' : '继续添加',
+ 'multiimage.searchBtn' : '搜索一下',
+ 'multiimage.searchPlaceholder' : '请输入搜索关键词',
+ 'multiimage.searchClear' : '清空搜索',
+ 'multiimage.noFileAdded' : '请至少添加一个文件!',
+ 'multiimage.uploading' : '正在上传',
+ 'multiimage.fileNotUpload' : '您还有文件没有上传!',
+ 'multiimage.uploadLimit' : '您本次最多上传 <%=uploadLimit%> 个文件.',
+ 'multiimage.sizeLimit' : '文件大小不能超过 <%=sizeLimit%> KB.',
+ 'multiimage.invalidExt' : '非法的文件后缀 <%=invalidExt%>.',
+ 'multiimage.remove' : '删除',
+ 'multiimage.rotateRight' : '向右旋转',
+ 'multiimage.rotateLeft' : '向左旋转',
+ 'multiimage.uploadFail' : '发生异常,上传失败!',
+ 'multiimage.noFileSelected' : '请至少选择一个文件或一张图片.',
+
+ 'filemanager.noDataText' : '(⊙o⊙)亲,没有多数据了。',
+ 'filemanager.title' : '文件服务器',
+ 'filemanager.noListUrl' : '无法获取图片,请先配置 fileManagerJson.',
+ 'filemanager.closeText' : '关闭对话框',
+ 'filemanager.confirmBtnText' : '确定',
+ 'filemanager.cancelBtnText' : '取消',
+ 'filemanager.loadMoreData' : '往下拉动滚动条可以加载更多数据.',
+ 'filemanager.depJQueryError' : '文件管理插件依赖 jQuery, 请先引入 jQuery.',
+ 'filemanager.fileType' : '类型',
+
+ 'graft.btnText' : '保存并插入涂鸦',
+ 'graft.uploadSuccess' : '涂鸦上传成功',
+ 'graft.uploadFaild' : '涂鸦上传失败',
+ 'graft.empty' : '您没有在画布上绘制任何图像',
+
+ 'insertfile.url' : 'URL',
+ 'insertfile.title' : '文件说明',
+ 'insertfile.upload' : '上传',
+ 'insertfile.viewServer' : '文件空间',
+ 'table.cells' : '单元格数',
+ 'table.rows' : '行数',
+ 'table.cols' : '列数',
+ 'table.size' : '大小',
+ 'table.width' : '宽度',
+ 'table.height' : '高度',
+ 'table.percent' : '%',
+ 'table.px' : 'px',
+ 'table.space' : '边距间距',
+ 'table.padding' : '边距',
+ 'table.spacing' : '间距',
+ 'table.align' : '对齐方式',
+ 'table.textAlign' : '水平对齐',
+ 'table.verticalAlign' : '垂直对齐',
+ 'table.alignDefault' : '默认',
+ 'table.alignLeft' : '左对齐',
+ 'table.alignCenter' : '居中',
+ 'table.alignRight' : '右对齐',
+ 'table.alignTop' : '顶部',
+ 'table.alignMiddle' : '中部',
+ 'table.alignBottom' : '底部',
+ 'table.alignBaseline' : '基线',
+ 'table.border' : '边框',
+ 'table.borderWidth' : '宽度',
+ 'table.borderColor' : '颜色',
+ 'table.backgroundColor' : '背景颜色',
+ 'map.address' : '地址: ',
+ 'map.search' : '搜索',
+ 'baidumap.address' : '地址: ',
+ 'baidumap.search' : '搜索',
+ 'baidumap.insertDynamicMap' : '插入动态地图',
+ 'anchor.name' : '锚点名称',
+ 'formatblock.formatBlock' : {
+ h1 : '标题 1',
+ h2 : '标题 2',
+ h3 : '标题 3',
+ h4 : '标题 4',
+ p : '正 文'
+ },
+ 'fontname.fontName' : {
+ 'SimSun' : '宋体',
+ 'NSimSun' : '新宋体',
+ 'FangSong' : '仿宋',
+ 'KaiTi' : '楷体',
+ 'SimHei' : '黑体',
+ 'Microsoft YaHei' : '微软雅黑',
+ 'Arial' : 'Arial',
+ 'Arial Black' : 'Arial Black',
+ 'Times New Roman' : 'Times New Roman',
+ 'Courier New' : 'Courier New',
+ 'Tahoma' : 'Tahoma',
+ 'Verdana' : 'Verdana'
+ },
+ 'lineheight.lineHeight' : [
+ {'1' : '单倍行距'},
+ {'1.5' : '1.5倍行距'},
+ {'2' : '2倍行距'},
+ {'2.5' : '2.5倍行距'},
+ {'3' : '3倍行距'}
+ ],
+ 'template.selectTemplate' : '可选模板',
+ 'template.replaceContent' : '替换当前内容',
+ 'template.fileList' : {
+ '1.html' : '图片和文字',
+ '2.html' : '表格',
+ '3.html' : '项目编号'
+ }
+}, 'zh-CN');
+KindEditor.options.langType = 'zh-CN';
diff --git a/addons/nkeditor/assets/lang/zh-TW.js b/addons/nkeditor/assets/lang/zh-TW.js
new file mode 100644
index 0000000000000000000000000000000000000000..49468980f618aab6f8ff4824df5bed50eea59663
--- /dev/null
+++ b/addons/nkeditor/assets/lang/zh-TW.js
@@ -0,0 +1,243 @@
+/*******************************************************************************
+* KindEditor - WYSIWYG HTML Editor for Internet
+* Copyright (C) 2006-2011 kindsoft.net
+*
+* @author Roddy
+* @site http://www.kindsoft.net/
+* @licence http://www.kindsoft.net/license.php
+*******************************************************************************/
+
+KindEditor.lang({
+ source : '原始碼',
+ preview : '預覽',
+ undo : '復原(Ctrl+Z)',
+ redo : '重複(Ctrl+Y)',
+ cut : '剪下(Ctrl+X)',
+ copy : '複製(Ctrl+C)',
+ paste : '貼上(Ctrl+V)',
+ plainpaste : '貼為純文字格式',
+ wordpaste : '自Word貼上',
+ selectall : '全選(Ctrl+A)',
+ justifyleft : '靠左對齊',
+ justifycenter : '置中',
+ justifyright : '靠右對齊',
+ justifyfull : '左右對齊',
+ insertorderedlist : '編號清單',
+ insertunorderedlist : '項目清單',
+ indent : '增加縮排',
+ outdent : '減少縮排',
+ subscript : '下標',
+ superscript : '上標',
+ formatblock : '標題',
+ fontname : '字體',
+ fontsize : '文字大小',
+ forecolor : '文字顏色',
+ hilitecolor : '背景顏色',
+ bold : '粗體(Ctrl+B)',
+ italic : '斜體(Ctrl+I)',
+ underline : '底線(Ctrl+U)',
+ strikethrough : '刪除線',
+ removeformat : '清除格式',
+ image : '影像',
+ multiimage : '批量影像上傳',
+ flash : 'Flash',
+ media : '多媒體',
+ table : '表格',
+ tablecell : '儲存格',
+ hr : '插入水平線',
+ emoticons : '插入表情',
+ link : '超連結',
+ unlink : '移除超連結',
+ fullscreen : '最大化',
+ about : '關於',
+ print : '列印(Ctrl+P)',
+ filemanager : '瀏覽伺服器',
+ code : '插入程式代碼',
+ map : 'Google地圖',
+ baidumap : 'Baidu地圖',
+ lineheight : '行距',
+ clearhtml : '清理HTML代碼',
+ pagebreak : '插入分頁符號',
+ quickformat : '快速排版',
+ insertfile : '插入文件',
+ template : '插入樣板',
+ anchor : '錨點',
+ yes : '確定',
+ no : '取消',
+ close : '關閉',
+ editImage : '影像屬性',
+ deleteImage : '刪除影像',
+ editFlash : 'Flash屬性',
+ deleteFlash : '删除Flash',
+ editMedia : '多媒體屬性',
+ deleteMedia : '删除多媒體',
+ editLink : '超連結屬性',
+ deleteLink : '移除超連結',
+ editAnchor : '锚点属性',
+ deleteAnchor : '删除锚点',
+ tableprop : '表格屬性',
+ tablecellprop : '儲存格屬性',
+ tableinsert : '插入表格',
+ tabledelete : '刪除表格',
+ tablecolinsertleft : '向左插入列',
+ tablecolinsertright : '向右插入列',
+ tablerowinsertabove : '向上插入欄',
+ tablerowinsertbelow : '下方插入欄',
+ tablerowmerge : '向下合併單元格',
+ tablecolmerge : '向右合併單元格',
+ tablerowsplit : '分割欄',
+ tablecolsplit : '分割列',
+ tablecoldelete : '删除列',
+ tablerowdelete : '删除欄',
+ noColor : '自動',
+ pleaseSelectFile : '請選擇文件。',
+ invalidImg : "請輸入有效的URL。\n只允許jpg,gif,bmp,png格式。",
+ invalidMedia : "請輸入有效的URL。\n只允許swf,flv,mp3,wav,wma,wmv,mid,avi,mpg,asf,rm,rmvb格式。",
+ invalidWidth : "寬度必須是數字。",
+ invalidHeight : "高度必須是數字。",
+ invalidBorder : "邊框必須是數字。",
+ invalidUrl : "請輸入有效的URL。",
+ invalidRows : '欄數是必須輸入項目,只允許輸入大於0的數字。',
+ invalidCols : '列數是必須輸入項目,只允許輸入大於0的數字。',
+ invalidPadding : '內距必須是數字。',
+ invalidSpacing : '間距必須是數字。',
+ invalidJson : '伺服器發生故障。',
+ uploadSuccess : '上傳成功。',
+ cutError : '您的瀏覽器安全設置不允許使用剪下操作,請使用快捷鍵(Ctrl+X)完成。',
+ copyError : '您的瀏覽器安全設置不允許使用剪下操作,請使用快捷鍵(Ctrl+C)完成。',
+ pasteError : '您的瀏覽器安全設置不允許使用剪下操作,請使用快捷鍵(Ctrl+V)完成。',
+ ajaxLoading : '加載中,請稍候 ...',
+ uploadLoading : '上傳中,請稍候 ...',
+ uploadError : '上傳錯誤',
+ 'plainpaste.comment' : '請使用快捷鍵(Ctrl+V)把內容貼到下方區域裡。',
+ 'wordpaste.comment' : '請使用快捷鍵(Ctrl+V)把內容貼到下方區域裡。',
+ 'code.pleaseInput' : 'Please input code.',
+ 'link.url' : 'URL',
+ 'link.linkType' : '打開類型',
+ 'link.newWindow' : '新窗口',
+ 'link.selfWindow' : '本頁窗口',
+ 'flash.url' : 'URL',
+ 'flash.width' : '寬度',
+ 'flash.height' : '高度',
+ 'flash.upload' : '上傳',
+ 'flash.viewServer' : '瀏覽',
+ 'media.url' : 'URL',
+ 'media.width' : '寬度',
+ 'media.height' : '高度',
+ 'media.autostart' : '自動播放',
+ 'media.upload' : '上傳',
+ 'media.viewServer' : '瀏覽',
+ 'image.remoteImage' : '網絡影像',
+ 'image.localImage' : '上傳影像',
+ 'image.remoteUrl' : '影像URL',
+ 'image.localUrl' : '影像URL',
+ 'image.size' : '影像大小',
+ 'image.width' : '寬度',
+ 'image.height' : '高度',
+ 'image.resetSize' : '原始大小',
+ 'image.align' : '對齊方式',
+ 'image.defaultAlign' : '未設定',
+ 'image.leftAlign' : '向左對齊',
+ 'image.rightAlign' : '向右對齊',
+ 'image.imgTitle' : '影像說明',
+ 'image.upload' : '瀏覽...',
+ 'image.viewServer' : '瀏覽...',
+ 'multiimage.uploadDesc' : 'Allows users to upload <%=uploadLimit%> images, single image size not exceeding <%=sizeLimit%>',
+ 'multiimage.startUpload' : 'Start upload',
+ 'multiimage.clearAll' : 'Clear all',
+ 'multiimage.insertAll' : 'Insert all',
+ 'multiimage.queueLimitExceeded' : 'Queue limit exceeded.',
+ 'multiimage.fileExceedsSizeLimit' : 'File exceeds size limit.',
+ 'multiimage.zeroByteFile' : 'Zero byte file.',
+ 'multiimage.invalidFiletype' : 'Invalid file type.',
+ 'multiimage.unknownError' : 'Unknown upload error.',
+ 'multiimage.pending' : 'Pending ...',
+ 'multiimage.uploadError' : 'Upload error',
+ 'filemanager.emptyFolder' : '空文件夾',
+ 'filemanager.moveup' : '至上一級文件夾',
+ 'filemanager.viewType' : '顯示方式:',
+ 'filemanager.viewImage' : '縮略圖',
+ 'filemanager.listImage' : '詳細信息',
+ 'filemanager.orderType' : '排序方式:',
+ 'filemanager.fileName' : '名稱',
+ 'filemanager.fileSize' : '大小',
+ 'filemanager.fileType' : '類型',
+ 'insertfile.url' : 'URL',
+ 'insertfile.title' : '文件說明',
+ 'insertfile.upload' : '上傳',
+ 'insertfile.viewServer' : '瀏覽',
+ 'table.cells' : '儲存格數',
+ 'table.rows' : '欄數',
+ 'table.cols' : '列數',
+ 'table.size' : '表格大小',
+ 'table.width' : '寬度',
+ 'table.height' : '高度',
+ 'table.percent' : '%',
+ 'table.px' : 'px',
+ 'table.space' : '內距間距',
+ 'table.padding' : '內距',
+ 'table.spacing' : '間距',
+ 'table.align' : '對齊方式',
+ 'table.textAlign' : '水平對齊',
+ 'table.verticalAlign' : '垂直對齊',
+ 'table.alignDefault' : '未設定',
+ 'table.alignLeft' : '向左對齊',
+ 'table.alignCenter' : '置中',
+ 'table.alignRight' : '向右對齊',
+ 'table.alignTop' : '靠上',
+ 'table.alignMiddle' : '置中',
+ 'table.alignBottom' : '靠下',
+ 'table.alignBaseline' : '基線',
+ 'table.border' : '表格邊框',
+ 'table.borderWidth' : '邊框',
+ 'table.borderColor' : '顏色',
+ 'table.backgroundColor' : '背景顏色',
+ 'map.address' : '住所: ',
+ 'map.search' : '尋找',
+ 'baidumap.address' : '住所: ',
+ 'baidumap.search' : '尋找',
+ 'baidumap.insertDynamicMap' : '插入動態地圖',
+ 'anchor.name' : '錨點名稱',
+ 'formatblock.formatBlock' : {
+ h1 : '標題 1',
+ h2 : '標題 2',
+ h3 : '標題 3',
+ h4 : '標題 4',
+ p : '一般'
+ },
+ 'fontname.fontName' : {
+ 'MingLiU' : '細明體',
+ 'PMingLiU' : '新細明體',
+ 'DFKai-SB' : '標楷體',
+ 'SimSun' : '宋體',
+ 'NSimSun' : '新宋體',
+ 'FangSong' : '仿宋體',
+ 'Arial' : 'Arial',
+ 'Arial Black' : 'Arial Black',
+ 'Times New Roman' : 'Times New Roman',
+ 'Courier New' : 'Courier New',
+ 'Tahoma' : 'Tahoma',
+ 'Verdana' : 'Verdana'
+ },
+ 'lineheight.lineHeight' : [
+ {'1' : '单倍行距'},
+ {'1.5' : '1.5倍行距'},
+ {'2' : '2倍行距'},
+ {'2.5' : '2.5倍行距'},
+ {'3' : '3倍行距'}
+ ],
+ 'template.selectTemplate' : '可選樣板',
+ 'template.replaceContent' : '取代當前內容',
+ 'template.fileList' : {
+ '1.html' : '影像和文字',
+ '2.html' : '表格',
+ '3.html' : '项目清單'
+ }
+}, 'zh-TW');
+
+KindEditor.each(KindEditor.options.items, function(i, name) {
+ if (name == 'baidumap') {
+ KindEditor.options.items[i] = 'map';
+ }
+});
+KindEditor.options.langType = 'zh-TW';
\ No newline at end of file
diff --git a/addons/nkeditor/assets/nkeditor.js b/addons/nkeditor/assets/nkeditor.js
new file mode 100644
index 0000000000000000000000000000000000000000..cb9d8d1de6316468d866e3409c2aa56ae42aee52
--- /dev/null
+++ b/addons/nkeditor/assets/nkeditor.js
@@ -0,0 +1,9503 @@
+/*******************************************************************************
+ * KindEditor - WYSIWYG HTML Editor for Internet
+ * Copyright (C) 2006-2018 kindsoft.net
+ *
+ * @author Roddy
+ * @website http://www.kindsoft.net/
+ * @licence http://www.kindsoft.net/license.php
+ * @version 5.0.3 (2018-10-25)
+ *******************************************************************************/
+(function (window, undefined) {
+ if (window.KindEditor) {
+ return;
+ }
+
+
+ if (!window.console) {
+ window.console = {};
+ }
+ if (!console.log) {
+ console.log = function () {
+ };
+ }
+ var _VERSION = '5.0.3 (2018-10-25)',
+ _ua = navigator.userAgent.toLowerCase(),
+ _IE = _ua.indexOf('msie') > -1 && _ua.indexOf('opera') == -1,
+ _NEWIE = _ua.indexOf('msie') == -1 && _ua.indexOf('trident') > -1,
+ _GECKO = _ua.indexOf('gecko') > -1 && _ua.indexOf('khtml') == -1,
+ _WEBKIT = _ua.indexOf('applewebkit') > -1,
+ _OPERA = _ua.indexOf('opera') > -1,
+ _MOBILE = _ua.indexOf('mobile') > -1,
+ _IOS = /ipad|iphone|ipod/.test(_ua),
+ _QUIRKS = document.compatMode != 'CSS1Compat',
+ _IERANGE = !window.getSelection,
+ _matches = /(?:msie|firefox|webkit|opera)[\/:\s](\d+)/.exec(_ua),
+ _V = _matches ? _matches[1] : '0',
+ _TIME = new Date().getTime();
+
+ function _isArray(val) {
+ if (!val) {
+ return false;
+ }
+ return Object.prototype.toString.call(val) === '[object Array]';
+ }
+
+ function _isFunction(val) {
+ if (!val) {
+ return false;
+ }
+ return Object.prototype.toString.call(val) === '[object Function]';
+ }
+
+ function _inArray(val, arr) {
+ for (var i = 0, len = arr.length; i < len; i++) {
+ if (val === arr[i]) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ function _each(obj, fn) {
+ if (_isArray(obj)) {
+ for (var i = 0, len = obj.length; i < len; i++) {
+ if (fn.call(obj[i], i, obj[i]) === false) {
+ break;
+ }
+ }
+ } else {
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ if (fn.call(obj[key], key, obj[key]) === false) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ function _trim(str) {
+ return str.replace(/(?:^[ \t\n\r]+)|(?:[ \t\n\r]+$)/g, '');
+ }
+
+ function _inString(val, str, delimiter) {
+ delimiter = delimiter === undefined ? ',' : delimiter;
+ return (delimiter + str + delimiter).indexOf(delimiter + val + delimiter) >= 0;
+ }
+
+ function _addUnit(val, unit) {
+ unit = unit || 'px';
+ return val && /^-?\d+(?:\.\d+)?$/.test(val) ? val + unit : val;
+ }
+
+ function _removeUnit(val) {
+ var match;
+ return val && (match = /(\d+)/.exec(val)) ? parseInt(match[1], 10) : 0;
+ }
+
+ function _escape(val) {
+ return val.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
+ }
+
+ function _unescape(val) {
+ return val.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/&/g, '&');
+ }
+
+ function _toCamel(str) {
+ var arr = str.split('-');
+ str = '';
+ _each(arr, function (key, val) {
+ str += (key > 0) ? val.charAt(0).toUpperCase() + val.substr(1) : val;
+ });
+ return str;
+ }
+
+ function _toHex(val) {
+ function hex(d) {
+ var s = parseInt(d, 10).toString(16).toUpperCase();
+ return s.length > 1 ? s : '0' + s;
+ }
+
+ return val.replace(/rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/ig,
+ function ($0, $1, $2, $3) {
+ return '#' + hex($1) + hex($2) + hex($3);
+ }
+ );
+ }
+
+ function _toMap(val, delimiter) {
+ delimiter = delimiter === undefined ? ',' : delimiter;
+ var map = {}, arr = _isArray(val) ? val : val.split(delimiter), match;
+ _each(arr, function (key, val) {
+ if ((match = /^(\d+)\.\.(\d+)$/.exec(val))) {
+ for (var i = parseInt(match[1], 10); i <= parseInt(match[2], 10); i++) {
+ map[i.toString()] = true;
+ }
+ } else {
+ map[val] = true;
+ }
+ });
+ return map;
+ }
+
+ function _toArray(obj, offset) {
+ return Array.prototype.slice.call(obj, offset || 0);
+ }
+
+ function _undef(val, defaultVal) {
+ return val === undefined ? defaultVal : val;
+ }
+
+ function _invalidUrl(url) {
+ return !url || /[<>"]/.test(url);
+ }
+
+ function _addParam(url, param) {
+ return url.indexOf('?') >= 0 ? url + '&' + param : url + '?' + param;
+ }
+
+ function _extend(child, parent, proto) {
+ if (!proto) {
+ proto = parent;
+ parent = null;
+ }
+ var childProto;
+ if (parent) {
+ var fn = function () {
+ };
+ fn.prototype = parent.prototype;
+ childProto = new fn();
+ _each(proto, function (key, val) {
+ childProto[key] = val;
+ });
+ } else {
+ childProto = proto;
+ }
+ childProto.constructor = child;
+ child.prototype = childProto;
+ child.parent = parent ? parent.prototype : null;
+ }
+
+
+ function _json(text) {
+ var match;
+ if ((match = /\{[\s\S]*\}|\[[\s\S]*\]/.exec(text))) {
+ text = match[0];
+ }
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+ if (/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+ return eval('(' + text + ')');
+ }
+ throw 'JSON parse error';
+ }
+
+
+ function _merge(distObj, obj) {
+ for (var name in distObj) {
+ obj[name] = distObj[name];
+ }
+ return obj;
+ }
+
+ var _round = Math.round;
+ var K = {
+ DEBUG: false,
+ VERSION: _VERSION,
+ IE: _IE,
+ GECKO: _GECKO,
+ WEBKIT: _WEBKIT,
+ OPERA: _OPERA,
+ V: _V,
+ TIME: _TIME,
+ each: _each,
+ isArray: _isArray,
+ isFunction: _isFunction,
+ inArray: _inArray,
+ inString: _inString,
+ trim: _trim,
+ addUnit: _addUnit,
+ removeUnit: _removeUnit,
+ escape: _escape,
+ unescape: _unescape,
+ toCamel: _toCamel,
+ toHex: _toHex,
+ toMap: _toMap,
+ toArray: _toArray,
+ undef: _undef,
+ invalidUrl: _invalidUrl,
+ addParam: _addParam,
+ extend: _extend,
+ merge: _merge,
+ json: _json
+ };
+ var _INLINE_TAG_MAP = _toMap('a,abbr,acronym,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,img,input,ins,kbd,label,map,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'),
+ _BLOCK_TAG_MAP = _toMap('address,applet,blockquote,body,center,dd,dir,div,dl,dt,fieldset,form,frameset,h1,h2,h3,h4,h5,h6,head,hr,html,iframe,ins,isindex,li,map,menu,meta,noframes,noscript,object,ol,p,pre,script,style,table,tbody,td,tfoot,th,thead,title,tr,ul'),
+ _SINGLE_TAG_MAP = _toMap('area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed'),
+ _STYLE_TAG_MAP = _toMap('b,basefont,big,del,em,font,i,s,small,span,strike,strong,sub,sup,u'),
+ _CONTROL_TAG_MAP = _toMap('img,table,input,textarea,button'),
+ _PRE_TAG_MAP = _toMap('pre,style,script'),
+ _NOSPLIT_TAG_MAP = _toMap('html,head,body,td,tr,table,ol,ul,li'),
+ _AUTOCLOSE_TAG_MAP = _toMap('colgroup,dd,dt,li,options,p,td,tfoot,th,thead,tr'),
+ _FILL_ATTR_MAP = _toMap('checked,compact,declare,defer,disabled,ismap,multiple,nohref,noresize,noshade,nowrap,readonly,selected'),
+ _VALUE_TAG_MAP = _toMap('input,button,textarea,select');
+
+
+ function _getBasePath() {
+ var els = document.getElementsByTagName('script'), src;
+ for (var i = 0, len = els.length; i < len; i++) {
+ src = els[i].src || '';
+ if (/NKeditor[\w\-\.]*\.js/i.test(src)) {
+ return src.substring(0, src.lastIndexOf('/') + 1);
+ }
+ }
+ return '';
+ }
+
+ K.basePath = _getBasePath();
+ K.options = {
+ designMode: true,
+ fullscreenMode: false,
+ filterMode: true,
+ wellFormatMode: true,
+ loadStyleMode: true,
+ basePath: K.basePath,
+ themesPath: K.basePath + 'themes/',
+ langPath: K.basePath + 'lang/',
+ pluginsPath: K.basePath + 'plugins/',
+ themeType: 'primary',
+ langType: 'zh-CN',
+ urlType: '',
+ newlineTag: 'p',
+ resizeType: 2,
+ syncType: 'form',
+ pasteType: 2,
+ dialogAlignType: 'page',
+ useContextmenu: true,
+ fullscreenShortcut: false,
+ bodyClass: 'ke-content',
+ indentChar: '\t',
+ cssPath: [],
+ jsPath: [],
+ showHelpGrid: false,
+ cssData: '',
+ minWidth: 650,
+ minHeight: 300,
+ minChangeSize: 50,
+ zIndex: 811213,
+ items: [
+ 'source', 'undo', 'redo', 'preview', 'print', 'template', 'code', 'quote', 'cut', 'copy', 'paste',
+ 'plainpaste', 'wordpaste', 'justifyleft', 'justifycenter', 'justifyright',
+ 'justifyfull', 'insertorderedlist', 'insertunorderedlist', 'indent', 'outdent', 'subscript',
+ 'superscript', 'clearhtml', 'quickformat', 'selectall',
+ 'formatblock', 'fontname', 'fontsize', 'forecolor', 'hilitecolor', 'bold',
+ 'italic', 'underline', 'strikethrough', 'lineheight', 'removeformat', 'image', 'multiimage', 'graft',
+ 'flash', 'media', 'insertfile', 'table', 'hr', 'emoticons', 'baidumap', 'pagebreak',
+ 'anchor', 'link', 'unlink', 'about', 'fullscreen'
+ ],
+ noDisableItems: ['source', 'fullscreen'],
+ colorTable: [
+ ['#E53333', '#E56600', '#FF9900', '#64451D', '#DFC5A4', '#FFE500'],
+ ['#009900', '#006600', '#99BB00', '#B8D100', '#60D978', '#00D5FF'],
+ ['#337FE5', '#003399', '#4C33E5', '#9933E5', '#CC33E5', '#EE33EE'],
+ ['#FFFFFF', '#DDDDDD', '#999999', '#666666', '#333333', '#000000']
+ ],
+ fontSizeTable: ['9px', '10px', '12px', '14px', '16px', '18px', '24px', '32px'],
+ htmlTags: {
+ font: ['id', 'class', 'color', 'size', 'face', '.background-color'],
+ span: [
+ 'id', 'class', '.color', '.background-color', '.font-size', '.font-family', '.background',
+ '.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.line-height'
+ ],
+ div: [
+ 'id', 'class', 'align', '.border', '.margin', '.padding', '.text-align', '.color',
+ '.background-color', '.font-size', '.font-family', '.font-weight', '.background',
+ '.font-style', '.text-decoration', '.vertical-align', '.margin-left'
+ ],
+ table: [
+ 'id', 'class', 'border', 'cellspacing', 'cellpadding', 'width', 'height', 'align', 'bordercolor',
+ '.padding', '.margin', '.border', 'bgcolor', '.text-align', '.color', '.background-color',
+ '.font-size', '.font-family', '.font-weight', '.font-style', '.text-decoration', '.background',
+ '.width', '.height', '.border-collapse'
+ ],
+ 'td,th': [
+ 'id', 'class', 'align', 'valign', 'width', 'height', 'colspan', 'rowspan', 'bgcolor',
+ '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.font-weight',
+ '.font-style', '.text-decoration', '.vertical-align', '.background', '.border'
+ ],
+ a: ['id', 'class', 'href', 'target', 'name'],
+ embed: ['id', 'class', 'src', 'width', 'height', 'type', 'loop', 'autostart', 'quality', '.width', '.height', 'align', 'allowscriptaccess', 'wmode', 'controls'],
+ img: ['id', 'class', 'src', 'width', 'height', 'border', 'alt', 'title', 'align', '.width', '.height', '.border'],
+ 'p,ol,ul,li,blockquote,h1,h2,h3,h4,h5,h6': [
+ 'id', 'class', 'align', '.text-align', '.color', '.background-color', '.font-size', '.font-family', '.background',
+ '.font-weight', '.font-style', '.text-decoration', '.vertical-align', '.text-indent', '.margin-left'
+ ],
+ pre: ['id', 'class'],
+ hr: ['id', 'class', '.page-break-after'],
+ 'br,tbody,tr,strong,b,sub,sup,em,i,u,strike,s,del': ['id', 'class'],
+ iframe: ['id', 'class', 'src', 'frameborder', 'width', 'height', '.width', '.height']
+ },
+ layout: '',
+ afterBlur: function () {
+ this.sync();
+ },
+ errorMsgHandler: function (message, type) {
+ console.log(message);
+ console.log(type);
+ alert(message);
+ },
+ dialogOffset: 0,
+ allowUploadGraft: true,
+ resLoadCache: {},
+ tableBorderColor: '#cccccc',
+ };
+
+
+ var _useCapture = false;
+
+
+ var _INPUT_KEY_MAP = _toMap('8,9,13,32,46,48..57,59,61,65..90,106,109..111,188,190..192,219..222');
+
+ var _CURSORMOVE_KEY_MAP = _toMap('33..40');
+
+ var _CHANGE_KEY_MAP = {};
+ _each(_INPUT_KEY_MAP, function (key, val) {
+ _CHANGE_KEY_MAP[key] = val;
+ });
+ _each(_CURSORMOVE_KEY_MAP, function (key, val) {
+ _CHANGE_KEY_MAP[key] = val;
+ });
+
+
+ function _bindEvent(el, type, fn) {
+ if (el.addEventListener) {
+ el.addEventListener(type, fn, _useCapture);
+ } else if (el.attachEvent) {
+ el.attachEvent('on' + type, fn);
+ }
+ }
+
+ function _unbindEvent(el, type, fn) {
+ if (el.removeEventListener) {
+ el.removeEventListener(type, fn, _useCapture);
+ } else if (el.detachEvent) {
+ el.detachEvent('on' + type, fn);
+ }
+ }
+
+ var _EVENT_PROPS = ('altKey,attrChange,attrName,bubbles,button,cancelable,charCode,clientX,clientY,ctrlKey,currentTarget,' +
+ 'data,detail,eventPhase,fromElement,handler,keyCode,metaKey,newValue,offsetX,offsetY,originalTarget,pageX,' +
+ 'pageY,prevValue,relatedNode,relatedTarget,screenX,screenY,shiftKey,srcElement,target,toElement,view,wheelDelta,which').split(',');
+
+
+ function KEvent(el, event) {
+ this.init(el, event);
+ }
+
+ _extend(KEvent, {
+ init: function (el, event) {
+ var self = this, doc = el.ownerDocument || el.document || el;
+ self.event = event;
+ _each(_EVENT_PROPS, function (key, val) {
+ self[val] = event[val];
+ });
+ if (!self.target) {
+ self.target = self.srcElement || doc;
+ }
+ if (self.target.nodeType === 3) {
+ self.target = self.target.parentNode;
+ }
+ if (!self.relatedTarget && self.fromElement) {
+ self.relatedTarget = self.fromElement === self.target ? self.toElement : self.fromElement;
+ }
+ if (self.pageX == null && self.clientX != null) {
+ var d = doc.documentElement, body = doc.body;
+ self.pageX = self.clientX + (d && d.scrollLeft || body && body.scrollLeft || 0) - (d && d.clientLeft || body && body.clientLeft || 0);
+ self.pageY = self.clientY + (d && d.scrollTop || body && body.scrollTop || 0) - (d && d.clientTop || body && body.clientTop || 0);
+ }
+ if (!self.which && ((self.charCode || self.charCode === 0) ? self.charCode : self.keyCode)) {
+ self.which = self.charCode || self.keyCode;
+ }
+ if (!self.metaKey && self.ctrlKey) {
+ self.metaKey = self.ctrlKey;
+ }
+ if (!self.which && self.button !== undefined) {
+ self.which = (self.button & 1 ? 1 : (self.button & 2 ? 3 : (self.button & 4 ? 2 : 0)));
+ }
+ switch (self.which) {
+ case 186 :
+ self.which = 59;
+ break;
+ case 187 :
+ case 107 :
+ case 43 :
+ self.which = 61;
+ break;
+ case 189 :
+ case 45 :
+ self.which = 109;
+ break;
+ case 42 :
+ self.which = 106;
+ break;
+ case 47 :
+ self.which = 111;
+ break;
+ case 78 :
+ self.which = 110;
+ break;
+ }
+ if (self.which >= 96 && self.which <= 105) {
+ self.which -= 48;
+ }
+ },
+ preventDefault: function () {
+ var ev = this.event;
+ if (ev.preventDefault) {
+ ev.preventDefault();
+ } else {
+ ev.returnValue = false;
+ }
+ },
+ stopPropagation: function () {
+ var ev = this.event;
+ if (ev.stopPropagation) {
+ ev.stopPropagation();
+ } else {
+ ev.cancelBubble = true;
+ }
+ },
+ stop: function () {
+ this.preventDefault();
+ this.stopPropagation();
+ }
+ });
+ var _eventExpendo = 'kindeditor_' + _TIME, _eventId = 0, _eventData = {};
+
+ function _getId(el) {
+ return el[_eventExpendo] || null;
+ }
+
+ function _setId(el) {
+ el[_eventExpendo] = ++_eventId;
+ return _eventId;
+ }
+
+ function _removeId(el) {
+ try {
+ delete el[_eventExpendo];
+ } catch (e) {
+ if (el.removeAttribute) {
+ el.removeAttribute(_eventExpendo);
+ }
+ }
+ }
+
+ function _bind(el, type, fn) {
+ if (type.indexOf(',') >= 0) {
+ _each(type.split(','), function () {
+ _bind(el, this, fn);
+ });
+ return;
+ }
+ var id = _getId(el);
+ if (!id) {
+ id = _setId(el);
+ }
+ if (_eventData[id] === undefined) {
+ _eventData[id] = {};
+ }
+ var events = _eventData[id][type];
+ if (events && events.length > 0) {
+ _unbindEvent(el, type, events[0]);
+ } else {
+ _eventData[id][type] = [];
+ _eventData[id].el = el;
+ }
+ events = _eventData[id][type];
+ if (events.length === 0) {
+ events[0] = function (e) {
+ var kevent = e ? new KEvent(el, e) : undefined;
+ _each(events, function (i, event) {
+ if (i > 0 && event) {
+ event.call(el, kevent);
+ }
+ });
+ };
+ }
+ if (_inArray(fn, events) < 0) {
+ events.push(fn);
+ }
+ _bindEvent(el, type, events[0]);
+ }
+
+ function _unbind(el, type, fn) {
+ if (type && type.indexOf(',') >= 0) {
+ _each(type.split(','), function () {
+ _unbind(el, this, fn);
+ });
+ return;
+ }
+ var id = _getId(el);
+ if (!id) {
+ return;
+ }
+ if (type === undefined) {
+ if (id in _eventData) {
+ _each(_eventData[id], function (key, events) {
+ if (key != 'el' && events.length > 0) {
+ _unbindEvent(el, key, events[0]);
+ }
+ });
+ delete _eventData[id];
+ _removeId(el);
+ }
+ return;
+ }
+ if (!_eventData[id]) {
+ return;
+ }
+ var events = _eventData[id][type];
+ if (events && events.length > 0) {
+ if (fn === undefined) {
+ _unbindEvent(el, type, events[0]);
+ delete _eventData[id][type];
+ } else {
+ _each(events, function (i, event) {
+ if (i > 0 && event === fn) {
+ events.splice(i, 1);
+ }
+ });
+ if (events.length == 1) {
+ _unbindEvent(el, type, events[0]);
+ delete _eventData[id][type];
+ }
+ }
+ var count = 0;
+ _each(_eventData[id], function () {
+ count++;
+ });
+ if (count < 2) {
+ delete _eventData[id];
+ _removeId(el);
+ }
+ }
+ }
+
+ function _fire(el, type) {
+ if (type.indexOf(',') >= 0) {
+ _each(type.split(','), function () {
+ _fire(el, this);
+ });
+ return;
+ }
+ var id = _getId(el);
+ if (!id) {
+ return;
+ }
+ var events = _eventData[id][type];
+ if (_eventData[id] && events && events.length > 0) {
+ events[0]();
+ }
+ }
+
+ function _ctrl(el, key, fn) {
+ var self = this;
+ key = /^\d{2,}$/.test(key) ? key : key.toUpperCase().charCodeAt(0);
+ _bind(el, 'keydown', function (e) {
+ if (e.ctrlKey && e.which == key && !e.shiftKey && !e.altKey) {
+ fn.call(el);
+ e.stop();
+ }
+ });
+ }
+
+ var _readyFinished = false;
+
+ function _ready(fn) {
+ if (_readyFinished) {
+ fn(KindEditor);
+ return;
+ }
+ var loaded = false;
+
+ function readyFunc() {
+ if (!loaded) {
+ loaded = true;
+ fn(KindEditor);
+ _readyFinished = true;
+ }
+ }
+
+ function ieReadyFunc() {
+ if (!loaded) {
+ try {
+ document.documentElement.doScroll('left');
+ } catch (e) {
+ setTimeout(ieReadyFunc, 100);
+ return;
+ }
+ readyFunc();
+ }
+ }
+
+ function ieReadyStateFunc() {
+ if (document.readyState === 'complete') {
+ readyFunc();
+ }
+ }
+
+ if (document.addEventListener) {
+ _bind(document, 'DOMContentLoaded', readyFunc);
+ } else if (document.attachEvent) {
+ _bind(document, 'readystatechange', ieReadyStateFunc);
+ var toplevel = false;
+ try {
+ toplevel = window.frameElement == null;
+ } catch (e) {
+ }
+ if (document.documentElement.doScroll && toplevel) {
+ ieReadyFunc();
+ }
+ }
+ _bind(window, 'load', readyFunc);
+ }
+
+ if (window.attachEvent) {
+ window.attachEvent('onunload', function () {
+ _each(_eventData, function (key, events) {
+ if (events.el) {
+ _unbind(events.el);
+ }
+ });
+ });
+ }
+ K.ctrl = _ctrl;
+ K.ready = _ready;
+
+ function _getCssList(css) {
+ css = css.replace(/"/g, '"');
+ var list = {},
+ reg = /\s*([\w\-]+)\s*:([^;]*)(;|$)/g,
+ match;
+ while ((match = reg.exec(css))) {
+ var key = _trim(match[1].toLowerCase()),
+ val = _trim(_toHex(match[2]));
+ list[key] = val;
+ }
+ return list;
+ }
+
+ function _getAttrList(tag) {
+ var list = {},
+ reg = /\s+(?:([\w\-:]+)|(?:([\w\-:]+)=([^\s"'<>]+))|(?:([\w\-:"]+)="([^"]*)")|(?:([\w\-:"]+)='([^']*)'))(?=(?:\s|\/|>)+)/g,
+ match;
+ while ((match = reg.exec(tag))) {
+ var key = (match[1] || match[2] || match[4] || match[6]).toLowerCase(),
+ val = (match[2] ? match[3] : (match[4] ? match[5] : match[7])) || '';
+ list[key] = val;
+ }
+ return list;
+ }
+
+ function _addClassToTag(tag, className) {
+ if (/\s+class\s*=/.test(tag)) {
+ tag = tag.replace(/(\s+class=["']?)([^"']*)(["']?[\s>])/, function ($0, $1, $2, $3) {
+ if ((' ' + $2 + ' ').indexOf(' ' + className + ' ') < 0) {
+ return $2 === '' ? $1 + className + $3 : $1 + $2 + ' ' + className + $3;
+ } else {
+ return $0;
+ }
+ });
+ } else {
+ tag = tag.substr(0, tag.length - 1) + ' class="' + className + '">';
+ }
+ return tag;
+ }
+
+ function _formatCss(css) {
+ var str = '';
+ _each(_getCssList(css), function (key, val) {
+ str += key + ':' + val + ';';
+ });
+ return str;
+ }
+
+ function _formatUrl(url, mode, host, pathname) {
+ mode = _undef(mode, '').toLowerCase();
+ if (url.substr(0, 5) != 'data:') {
+ url = url.replace(/([^:])\/\//g, '$1/');
+ }
+ if (_inArray(mode, ['absolute', 'relative', 'domain']) < 0) {
+ return url;
+ }
+ host = host || location.protocol + '//' + location.host;
+ if (pathname === undefined) {
+ var m = location.pathname.match(/^(\/.*)\//);
+ pathname = m ? m[1] : '';
+ }
+ var match;
+ if ((match = /^(\w+:\/\/[^\/]*)/.exec(url))) {
+ if (match[1] !== host) {
+ return url;
+ }
+ } else if (/^\w+:/.test(url)) {
+ return url;
+ }
+
+ function getRealPath(path) {
+ var parts = path.split('/'), paths = [];
+ for (var i = 0, len = parts.length; i < len; i++) {
+ var part = parts[i];
+ if (part == '..') {
+ if (paths.length > 0) {
+ paths.pop();
+ }
+ } else if (part !== '' && part != '.') {
+ paths.push(part);
+ }
+ }
+ return '/' + paths.join('/');
+ }
+
+ if (/^\//.test(url)) {
+ url = host + getRealPath(url.substr(1));
+ } else if (!/^\w+:\/\//.test(url)) {
+ url = host + getRealPath(pathname + '/' + url);
+ }
+
+ function getRelativePath(path, depth) {
+ if (url.substr(0, path.length) === path) {
+ var arr = [];
+ for (var i = 0; i < depth; i++) {
+ arr.push('..');
+ }
+ var prefix = '.';
+ if (arr.length > 0) {
+ prefix += '/' + arr.join('/');
+ }
+ if (pathname == '/') {
+ prefix += '/';
+ }
+ return prefix + url.substr(path.length);
+ } else {
+ if ((match = /^(.*)\//.exec(path))) {
+ return getRelativePath(match[1], ++depth);
+ }
+ }
+ }
+
+ if (mode === 'relative') {
+ url = getRelativePath(host + pathname, 0).substr(2);
+ } else if (mode === 'absolute') {
+ if (url.substr(0, host.length) === host) {
+ url = url.substr(host.length);
+ }
+ }
+ return url;
+ }
+
+ function _formatHtml(html, htmlTags, urlType, wellFormatted, indentChar) {
+ if (html == null) {
+ html = '';
+ }
+ urlType = urlType || '';
+ wellFormatted = _undef(wellFormatted, false);
+ indentChar = _undef(indentChar, '\t');
+ var fontSizeList = 'xx-small,x-small,small,medium,large,x-large,xx-large'.split(',');
+ html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function ($0, $1, $2, $3) {
+ return $1 + $2.replace(/<(?:br|br\s[^>]*)>/ig, '\n') + $3;
+ });
+ html = html.replace(/<(?:br|br\s[^>]*)\s*\/?>\s*<\/p>/ig, '
');
+ html = html.replace(/(<(?:p|p\s[^>]*)>)\s*(<\/p>)/ig, '$1 $2');
+ html = html.replace(/\u200B/g, '');
+ html = html.replace(/\u00A9/g, '©');
+ html = html.replace(/\u00AE/g, '®');
+ html = html.replace(/\u2003/g, ' ');
+ html = html.replace(/\u3000/g, ' ');
+ html = html.replace(/<[^>]+/g, function ($0) {
+ return $0.replace(/\s+/g, ' ');
+ });
+ var htmlTagMap = {};
+ if (htmlTags) {
+ _each(htmlTags, function (key, val) {
+ var arr = key.split(',');
+ for (var i = 0, len = arr.length; i < len; i++) {
+ htmlTagMap[arr[i]] = _toMap(val);
+ }
+ });
+ if (!htmlTagMap.script) {
+ html = html.replace(/(<(?:script|script\s[^>]*)>)([\s\S]*?)(<\/script>)/ig, '');
+ }
+ if (!htmlTagMap.style) {
+ html = html.replace(/(<(?:style|style\s[^>]*)>)([\s\S]*?)(<\/style>)/ig, '');
+ }
+ }
+ var re = /(\s*)<(\/)?([\w\-:]+)((?:\s+|(?:\s+[\w\-:]+)|(?:\s+[\w\-:]+=[^\s"'<>]+)|(?:\s+[\w\-:"]+="[^"]*")|(?:\s+[\w\-:"]+='[^']*'))*)(\/)?>(\s*)/g;
+ var tagStack = [];
+ html = html.replace(re, function ($0, $1, $2, $3, $4, $5, $6) {
+ var full = $0,
+ startNewline = $1 || '',
+ startSlash = $2 || '',
+ tagName = $3.toLowerCase(),
+ attr = $4 || '',
+ endSlash = $5 ? ' ' + $5 : '',
+ endNewline = $6 || '';
+ if (tagName == 'code') {
+ return full;
+ }
+ if (htmlTags && !htmlTagMap[tagName]) {
+ return '';
+ }
+ if (endSlash === '' && _SINGLE_TAG_MAP[tagName]) {
+ endSlash = ' /';
+ }
+ if (_INLINE_TAG_MAP[tagName]) {
+ if (startNewline) {
+ startNewline = ' ';
+ }
+ if (endNewline) {
+ endNewline = ' ';
+ }
+ }
+ if (_PRE_TAG_MAP[tagName]) {
+ if (startSlash) {
+ endNewline = '\n';
+ } else {
+ startNewline = '\n';
+ }
+ }
+ if (wellFormatted && tagName == 'br') {
+ endNewline = '\n';
+ }
+ if (_BLOCK_TAG_MAP[tagName] && !_PRE_TAG_MAP[tagName]) {
+ if (wellFormatted) {
+ if (startSlash && tagStack.length > 0 && tagStack[tagStack.length - 1] === tagName) {
+ tagStack.pop();
+ } else {
+ tagStack.push(tagName);
+ }
+ startNewline = '\n';
+ endNewline = '\n';
+ for (var i = 0, len = startSlash ? tagStack.length : tagStack.length - 1; i < len; i++) {
+ startNewline += indentChar;
+ if (!startSlash) {
+ endNewline += indentChar;
+ }
+ }
+ if (endSlash) {
+ tagStack.pop();
+ } else if (!startSlash) {
+ endNewline += indentChar;
+ }
+ } else {
+ startNewline = endNewline = '';
+ }
+ }
+ if (attr !== '') {
+ var attrMap = _getAttrList(full);
+ if (tagName === 'font') {
+ var fontStyleMap = {}, fontStyle = '';
+ _each(attrMap, function (key, val) {
+ if (key === 'color') {
+ fontStyleMap.color = val;
+ delete attrMap[key];
+ }
+ if (key === 'size') {
+ fontStyleMap['font-size'] = fontSizeList[parseInt(val, 10) - 1] || '';
+ delete attrMap[key];
+ }
+ if (key === 'face') {
+ fontStyleMap['font-family'] = val;
+ delete attrMap[key];
+ }
+ if (key === 'style') {
+ fontStyle = val;
+ }
+ });
+ if (fontStyle && !/;$/.test(fontStyle)) {
+ fontStyle += ';';
+ }
+ _each(fontStyleMap, function (key, val) {
+ if (val === '') {
+ return;
+ }
+ if (/\s/.test(val)) {
+ val = "'" + val + "'";
+ }
+ fontStyle += key + ':' + val + ';';
+ });
+ attrMap.style = fontStyle;
+ }
+ _each(attrMap, function (key, val) {
+ if (_FILL_ATTR_MAP[key]) {
+ attrMap[key] = key;
+ }
+ if (_inArray(key, ['src', 'href']) >= 0) {
+ attrMap[key] = _formatUrl(val, urlType);
+ }
+ if (htmlTags && key !== 'style' && !htmlTagMap[tagName]['*'] && !htmlTagMap[tagName][key] ||
+ tagName === 'body' && key === 'contenteditable' ||
+ /^kindeditor_\d+$/.test(key)) {
+ delete attrMap[key];
+ }
+ if (key === 'style' && val !== '') {
+ var styleMap = _getCssList(val);
+ _each(styleMap, function (k, v) {
+ if (htmlTags && !htmlTagMap[tagName].style && !htmlTagMap[tagName]['.' + k]) {
+ delete styleMap[k];
+ }
+ });
+ var style = '';
+ _each(styleMap, function (k, v) {
+ style += k + ':' + v + ';';
+ });
+ attrMap.style = style;
+ }
+ });
+ attr = '';
+ _each(attrMap, function (key, val) {
+ if (key === 'style' && val === '') {
+ return;
+ }
+ val = val.replace(/"/g, '"');
+ attr += ' ' + key + '="' + val + '"';
+ });
+ }
+ if (tagName === 'font') {
+ tagName = 'span';
+ }
+ return startNewline + '<' + startSlash + tagName + attr + endSlash + '>' + endNewline;
+ });
+ html = html.replace(/(<(?:pre|pre\s[^>]*)>)([\s\S]*?)(<\/pre>)/ig, function ($0, $1, $2, $3) {
+ return $1 + $2.replace(/\n/g, '\n') + $3;
+ });
+ html = html.replace(/\n\s*\n/g, '\n');
+ html = html.replace(/\n/g, '\n');
+ return _trim(html);
+ }
+
+ function _clearMsWord(html, htmlTags) {
+ html = html.replace(/ /ig, '')
+ .replace(//ig, '')
+ .replace(/');
+ if (!_isArray(cssPath)) {
+ cssPath = [cssPath];
+ }
+ if (_inArray(K.basePath + 'themes/app.css', cssPath) < 0) {
+ cssPath.push(K.basePath + 'themes/app.css');
+ }
+ _each(cssPath, function (i, path) {
+ if (path) {
+ arr.push(' ');
+ }
+ });
+ if (cssData) {
+ arr.push('');
+ }
+ arr.push('');
+ if (!_isArray(jsPath)) {
+ jsPath = [jsPath];
+ }
+ _each(jsPath, function (i, path) {
+ if (path) {
+ arr.push('');
+ }
+ });
+ arr.push('