zhangguidong před 2 roky
rodič
revize
87d2a6a86d
100 změnil soubory, kde provedl 8703 přidání a 6 odebrání
  1. 66 0
      application/store/controller/Hospital.php
  2. 40 1
      application/store/view/hospital/index_search.html
  3. 2 1
      composer.json
  4. 34 0
      store_sms.sql
  5. 91 0
      vendor/aliyuncs/oss-sdk-php/samples/BucketCname.php
  6. 98 0
      vendor/aliyuncs/oss-sdk-php/samples/BucketEncryption.php
  7. 116 0
      vendor/aliyuncs/oss-sdk-php/samples/BucketPayment.php
  8. 123 0
      vendor/aliyuncs/oss-sdk-php/samples/BucketPolicy.php
  9. 112 0
      vendor/aliyuncs/oss-sdk-php/samples/BucketTags.php
  10. 61 0
      vendor/aliyuncs/oss-sdk-php/samples/BucketTransferAcceleration.php
  11. 235 0
      vendor/aliyuncs/oss-sdk-php/samples/BucketVersion.php
  12. 145 0
      vendor/aliyuncs/oss-sdk-php/samples/BucketWorm.php
  13. 366 0
      vendor/aliyuncs/oss-sdk-php/samples/ObjectTagging.php
  14. 105 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Model/CnameTokenInfo.php
  15. 147 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Model/ObjectListInfoV2.php
  16. 73 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Model/TransferAccelerationConfig.php
  17. 19 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Result/CreateBucketCnameTokenResult.php
  18. 19 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Result/GetBucketCnameTokenResult.php
  19. 22 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Result/GetBucketTransferAccelerationResult.php
  20. 72 0
      vendor/aliyuncs/oss-sdk-php/src/OSS/Result/ListObjectsV2Result.php
  21. 31 0
      vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/CnameTokenInfoTest.php
  22. 61 0
      vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetBucketTransferAccelerationResultTest.php
  23. 154 0
      vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListObjectsV2ResultTest.php
  24. 61 0
      vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketCnameTest.php
  25. 40 0
      vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketTransferAccelerationTest.php
  26. 175 0
      vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientListObjectsV2Test.php
  27. 56 0
      vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/TransferAccelerationConfigTest.php
  28. 2 0
      vendor/composer/autoload_files.php
  29. 1 0
      vendor/composer/autoload_namespaces.php
  30. 8 0
      vendor/composer/autoload_psr4.php
  31. 59 0
      vendor/composer/autoload_static.php
  32. 717 0
      vendor/composer/installed.json
  33. 92 2
      vendor/composer/installed.php
  34. 2 2
      vendor/composer/platform_check.php
  35. 9 0
      vendor/ezyang/htmlpurifier/CREDITS
  36. 504 0
      vendor/ezyang/htmlpurifier/LICENSE
  37. 29 0
      vendor/ezyang/htmlpurifier/README.md
  38. 1 0
      vendor/ezyang/htmlpurifier/VERSION
  39. 25 0
      vendor/ezyang/htmlpurifier/composer.json
  40. 11 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php
  41. 14 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.autoload-legacy.php
  42. 25 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.autoload.php
  43. 4 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.composer.php
  44. 25 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.func.php
  45. 234 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php
  46. 30 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.kses.php
  47. 11 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php
  48. 297 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.php
  49. 228 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php
  50. 71 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php
  51. 148 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php
  52. 144 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php
  53. 136 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php
  54. 34 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php
  55. 113 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php
  56. 157 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php
  57. 56 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php
  58. 161 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php
  59. 48 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php
  60. 44 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php
  61. 77 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php
  62. 176 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php
  63. 219 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php
  64. 32 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php
  65. 56 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php
  66. 77 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php
  67. 112 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php
  68. 71 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php
  69. 90 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php
  70. 54 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php
  71. 46 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php
  72. 77 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php
  73. 44 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php
  74. 73 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php
  75. 48 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php
  76. 48 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php
  77. 51 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php
  78. 38 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php
  79. 113 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php
  80. 56 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php
  81. 72 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php
  82. 60 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php
  83. 70 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php
  84. 76 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php
  85. 91 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php
  86. 86 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php
  87. 53 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php
  88. 21 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php
  89. 111 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php
  90. 20 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php
  91. 29 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php
  92. 142 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php
  93. 45 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php
  94. 89 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php
  95. 60 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php
  96. 28 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Background.php
  97. 27 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php
  98. 28 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php
  99. 47 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php
  100. 26 0
      vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php

+ 66 - 0
application/store/controller/Hospital.php

@@ -3,6 +3,8 @@
 namespace app\store\controller;
 use library\Controller;
 use think\Db;
+use PhpOffice\PhpSpreadsheet\IOFactory;
+use PhpOffice\PhpSpreadsheet\Shared\Date;
 
 class Hospital extends  Controller
 {
@@ -106,4 +108,68 @@ class Hospital extends  Controller
         return $add;
     }
 
+    public function import(){
+        set_time_limit(60);//限制页面执行时间60s
+        $file = $_FILES['file']['tmp_name'];//临时文件路径或者文件url
+        try{
+            $file = iconv("utf-8", "gb2312", $file);//转码
+            if (empty($file) OR !file_exists($file)) {
+                throw new \Exception('文件不存在!');
+            }
+            $objReader = IOFactory::createReader('Xlsx');
+            if (!$objReader->canRead($file)) {
+                $objReader = IOFactory::createReader('Xls');
+                if (!$objReader->canRead($file)) {
+                    throw new \Exception('只支持导入Excel文件!');
+                }
+            }
+            $objReader->setReadDataOnly(true);//忽略任何格式的信息
+            $objPHPExcel = $objReader->load($file);
+            $worksheet = $objPHPExcel->getActiveSheet();
+            $sheet = $objPHPExcel->getSheet(0);   //excel中的第一张sheet
+            $highestRow = $sheet->getHighestRow();       // 取得总行数
+            // $highestColumn = $sheet->getHighestColumn();   // 取得总列数
+            /**
+             * 必填:    姓名 手机号 性别 报读院校 报读专业 报读层次 收件信息
+             * 非必填:  民族 政治面貌 户口所在地(市区) 考试县区 身份证号码 考前学历 毕业院校 毕业时间(年月) 毕业证书编号 毕业专业
+             */
+            $genders = [ 0 => '保密', 1 => '男', 2 => '女'];
+            $data = [];
+            $msg = '';
+            //$keys = ['name', 'phone', 'gender','end_date'];
+
+            for ($j = 2; $j <= $highestRow; $j++) {
+                //foreach ($keys as $k => $v) {
+                //    $$v = $worksheet->getCellByColumnAndRow($k + 1, $j)->getValue();
+                //}
+                $name = $worksheet->getCellByColumnAndRow(1, $j)->getValue();
+                $phone = $worksheet->getCellByColumnAndRow(2, $j)->getValue();
+                $gender= $worksheet->getCellByColumnAndRow(3, $j)->getValue();
+                $gender = array_search($gender, $genders);
+                $end_date = $worksheet->getCellByColumnAndRow(4, $j)->getValue();
+                //$end_date = date('Y-m-d', ($value - 25569) * 24 * 3600)
+                $end_date = date('Y-m-d', Date::excelToTimestamp($end_date));//转化为时间类型
+                //$name = $worksheet->getCell("A" . $j)->getValue();
+                //$phone = $worksheet->getCell("B" . $j)->getValue();
+                //$gender =  $worksheet->getCell("C" . $j)->getValue();
+                if (empty($name)) {
+                    $msg .=  '<p style="color:red">第'.($j-1).'条数据,姓名没有填写,插入失败</p>';
+                } else {
+                    $data[] = [
+                        'name' => $name,
+                        'phone' => $phone,
+                        'gender' => $gender,
+                        'end_date ' => $end_date ,
+                    ];
+                }
+            }
+            $res = Db::name('User')->data($data)->limit(100)->insertAll();// 分批插入数据
+            $msg .= '<p style="color:blue">导入完成</p><p style="color:blue">总共'.($highestRow-1).'条数据</p><p style="color:blue">成功'.count($data).'条数据</p><p style="color:red">失败'.($highestRow-count($data)-1).'条数据</p>';
+            return json(['code'=>1, 'msg'=>$msg]);
+        } catch (\Exception $e) {
+            return json(['code'=>0, 'msg'=>$e->getMessage()]);
+        }
+    }
+
+
 }

+ 40 - 1
application/store/view/hospital/index_search.html

@@ -13,6 +13,45 @@
         <div class="layui-form-item layui-inline">
             <button class="layui-btn layui-btn-primary"><i class="layui-icon">&#xe615;</i> 搜 索</button>
         </div>
+        <div class="layui-form-item layui-inline">
+
+        <button type="button" class="layui-btn layui-btn-sm layui-btn-normal" id="upload" style="margin-right: 10px;">
+            <i class="layui-icon">&#xe67c;</i>批量导入
+        </button>
+        </div>
     </form>
-    <script>form.render()</script>
+    <script>form.render()
+    layui.use('upload', function(){
+        var upload = layui.upload;
+        //执行实例
+        var uploadInst = upload.render({
+            elem: '#upload' //绑定元素
+            ,url: "{:url('import')}" //上传接口
+            , method: 'POST'
+            ,accept: 'file'//指定允许上传时校验的文件类型,可选值有:images(图片)、file(所有文件)、video(视频)、audio(音频)
+            ,exts: 'xlsx|xls'//只允许上传excel文件,未设定,那么限制的就是图片的文件格式
+            ,before: function(obj){ //obj参数包含的信息,跟 choose回调完全一致,可参见上文。
+                layer.load(); //上传loading
+            }
+            ,done: function(res){
+                layer.closeAll('loading'); //关闭loading
+                //上传完毕回调
+                console.log(res)
+                if(res.code == 1){
+                    layer.open({
+                        title: '导入结果'
+                        ,content: res.msg
+                        ,btn:['确定']
+                        ,yes:function(index, layero){
+                            location.reload();//刷新单前页
+                        }
+                    });
+                }else{
+                    layer.msg(res.msg, {icon: 5});
+                }
+            }
+        });
+    });
+
+    </script>
 </fieldset>

+ 2 - 1
composer.json

@@ -22,7 +22,8 @@
     "zoujingli/think-library": "5.1.x-dev",
     "zoujingli/weopen-developer": "dev-master",
     "firebase/php-jwt": "^5.2",
-    "phpoffice/phpexcel": "1.8"
+    "phpoffice/phpexcel": "1.8",
+    "phpoffice/phpspreadsheet": "^1.24"
   },
   "repositories": {
     "packagist": {

+ 34 - 0
store_sms.sql

@@ -0,0 +1,34 @@
+/*
+ Navicat Premium Data Transfer
+
+ Source Server         : 万物元宇宙
+ Source Server Type    : MySQL
+ Source Server Version : 50650
+ Source Host           : 114.55.32.67:3306
+ Source Schema         : wanwu
+
+ Target Server Type    : MySQL
+ Target Server Version : 50650
+ File Encoding         : 65001
+
+ Date: 22/07/2022 16:26:02
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for store_sms
+-- ----------------------------
+DROP TABLE IF EXISTS `store_sms`;
+CREATE TABLE `store_sms`  (
+  `id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
+  `event` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '类型',
+  `mobile` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '手机号',
+  `code` int(11) NULL DEFAULT NULL COMMENT '验证码',
+  `ip` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'ip',
+  `createtime` int(11) NULL DEFAULT NULL COMMENT '时间',
+  PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 21051 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '短信表' ROW_FORMAT = DYNAMIC;
+
+SET FOREIGN_KEY_CHECKS = 1;

+ 91 - 0
vendor/aliyuncs/oss-sdk-php/samples/BucketCname.php

@@ -0,0 +1,91 @@
+<?php
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+
+$bucket = Common::getBucketName();
+$ossClient = Common::getOssClient();
+if (is_null($ossClient)) exit(1);
+
+//*******************************Simple Usage ***************************************************************
+
+// Add Canme record
+$myDomain = '<yourDomainName>';
+$ossClient->addBucketCname($bucket, $myDomain);
+
+// View cname records
+$cnameConfig = $ossClient->getBucketCname($bucket);
+Common::println("bucket $bucket cname:" . $cnameConfig->serializeToXml());
+
+// Delete bucket cname
+$myDomain = '<yourDomainName>';
+$ossClient->deleteBucketCname($bucket,$myDomain);
+Common::println("bucket $bucket cname deleted");
+
+//******************************* For complete usage, see the following functions ****************************************************
+
+addBucketCname($ossClient, $bucket);
+getBucketCname($ossClient, $bucket);
+deleteBucketCname($ossClient, $bucket);
+
+/**
+ * Set bucket cname
+ *
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket bucket name
+ * @return null
+ */
+function addBucketCname($ossClient, $bucket)
+{
+	// Set up a custom domain name.
+	$myDomain = '<yourDomainName>';
+	try {
+		$ossClient->addBucketCname($bucket, $myDomain);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * Get bucket cname
+ *
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket bucket name
+ * @return null
+ */
+function getBucketCname($ossClient, $bucket)
+{
+    try {
+		$cnameConfig = $ossClient->getBucketCname($bucket);
+    } catch (OssException $e) {
+        printf(__FUNCTION__ . ": FAILED\n");
+        printf($e->getMessage() . "\n");
+        return;
+    }
+    print(__FUNCTION__ . ": OK" . "\n");
+    print($cnameConfig->serializeToXml() . "\n");
+}
+
+/**
+ * Delete bucket cname
+ *
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket bucket name
+ * @return null
+ */
+function deleteBucketCname($ossClient, $bucket)
+{
+	$myDomain = '<yourDomainName>';
+    try {
+		$ossClient->deleteBucketCname($bucket, $myDomain);
+    } catch (OssException $e) {
+        printf(__FUNCTION__ . ": FAILED\n");
+        printf($e->getMessage() . "\n");
+        return;
+    }
+    print(__FUNCTION__ . ": OK" . "\n");
+}

+ 98 - 0
vendor/aliyuncs/oss-sdk-php/samples/BucketEncryption.php

@@ -0,0 +1,98 @@
+<?php
+
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+use OSS\Model\ServerSideEncryptionConfig;
+
+$ossClient = Common::getOssClient();
+if (is_null($ossClient)) exit(1);
+$bucket = Common::getBucketName();
+
+//******************************* Simple Usage****************************************************************
+
+// Configure Bucket encryption
+// Set Bucket's default server-side encryption method to OSS fully managed encryption (SSE-OSS).
+$config = new ServerSideEncryptionConfig("AES256");
+// Set Bucket's default server-side encryption method to KMS, and do not specify a CMK ID.
+//$config = new ServerSideEncryptionConfig("KMS");
+// Set Bucket's default server-side encryption method to KMS, and specify the CMK ID.
+//$config = new ServerSideEncryptionConfig("KMS", "your kms id");
+$ossClient->putBucketEncryption($bucket, $config);
+Common::println("bucket $bucket encryoption created");
+
+$config = $ossClient->getBucketEncryption($bucket);
+Common::println("bucket $bucket encryoption:".$config->serializeToXml());
+
+$config = $ossClient->deleteBucketEncryption($bucket);
+Common::println("bucket $bucket encryoption has deleted");
+
+//******************************* For complete usage, see the following functions ****************************************************
+putBucketEncryption($ossClient, $bucket);
+getBucketEncryption($ossClient, $bucket);
+deleteBucketEncryption($ossClient, $bucket);
+
+/**
+ * Configure Bucket encryption
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+
+function putBucketEncryption($ossClient,$bucket){
+	try {
+		// Set Bucket's default server-side encryption method to OSS fully managed encryption (SSE-OSS).
+		$config = new ServerSideEncryptionConfig("AES256");
+		// Set Bucket's default server-side encryption method to KMS, and do not specify a CMK ID.
+		//$config = new ServerSideEncryptionConfig("KMS");
+		// Set Bucket's default server-side encryption method to KMS, and specify the CMK ID.
+		//$config = new ServerSideEncryptionConfig("KMS", "your kms id");
+		$ossClient->putBucketEncryption($bucket, $config);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * Get Bucket encryption
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+
+function getBucketEncryption($ossClient,$bucket){
+	try {
+		$config = $ossClient->getBucketEncryption($bucket);
+		print($config->getSSEAlgorithm());
+		print($config->getKMSMasterKeyID());
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * Delete Bucket encryption
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+
+function deleteBucketEncryption($ossClient,$bucket){
+	try {
+		$ossClient->deleteBucketEncryption($bucket);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+

+ 116 - 0
vendor/aliyuncs/oss-sdk-php/samples/BucketPayment.php

@@ -0,0 +1,116 @@
+<?php
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+
+$ossClient = Common::getOssClient();
+if (is_null($ossClient)) exit(1);
+$bucket = Common::getBucketName();
+
+//******************************* Simple Usage****************************************************************
+
+//Set requester payment mode
+$ossClient->putBucketRequestPayment($bucket, "Requester");
+
+//Get requester payment mode configuration
+$payer = $ossClient->getBucketRequestPayment($bucket);
+Common::println("bucket $bucket Payer:".$payer.PHP_EOL);
+
+//Third-party paid access to Object
+$options = array(
+	OssClient::OSS_HEADERS => array(
+		OssClient::OSS_REQUEST_PAYER => 'requester',
+	));
+
+$content = "hello";
+$object = "object";
+
+//PutObject interface to specify the payer
+$ossClient->putObject($bucket, $object, $content, $options);
+
+// GetObject interface to specify the payer
+$ossClient->getObject($bucket, $object, $options);
+
+// DeleteObject interface to specify the payer
+$ossClient->deleteObject($bucket, $object, $options);
+
+//******************************* For complete usage, see the following functions ****************************************************
+
+putBucketRequestPayment($ossClient,$bucket);
+getBucketRequestPayment($ossClient,$bucket);
+setObjectPayment($ossClient,$bucket);
+
+/**
+ * Set requester payment mode
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function putBucketRequestPayment($ossClient, $bucket)
+{
+	try {
+		$ossClient->putBucketRequestPayment($bucket, "Requester");
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * Get payment mode of bucket
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function getBucketRequestPayment($ossClient, $bucket)
+{
+	try {
+		$payer = $ossClient->getBucketRequestPayment($bucket);
+		print("bucket $bucket Payer:".$payer.PHP_EOL);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * Set payment mode of object
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function setObjectPayment($ossClient,$bucket){
+	// Specify the payment model for the requester.
+	$options = array(
+		OssClient::OSS_HEADERS => array(
+			OssClient::OSS_REQUEST_PAYER => 'requester',
+		));
+	
+	try {
+		
+		$content = "hello";
+		$object = "object";
+		//PutObject interface to specify the payer
+		$ossClient->putObject($bucket, $object, $content, $options);
+		// GetObject interface to specify the payer
+		$ossClient->getObject($bucket, $object, $options);
+		// DeleteObject interface to specify the payer
+		$ossClient->deleteObject($bucket, $object, $options);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+

+ 123 - 0
vendor/aliyuncs/oss-sdk-php/samples/BucketPolicy.php

@@ -0,0 +1,123 @@
+<?php
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+
+$ossClient = Common::getOssClient();
+if (is_null($ossClient)) exit(1);
+$bucket = Common::getBucketName();
+
+//******************************* Simple Usage****************************************************************
+
+// Set Bucket Policy
+// Authorization strategy.
+$policy = <<< BBBB
+{
+  "Version":"1",
+  "Statement":[
+  {
+    "Action":[
+    "oss:PutObject",
+    "oss:GetObject"
+  ],
+    "Effect":"Allow",
+    "Resource":["acs:oss:*:*:*/user1/*"]
+  }
+  ]
+}
+BBBB;
+$ossClient->putBucketPolicy($bucket, $policy);
+
+// Get bucket pllicy
+$policy = $ossClient->getBucketPolicy($bucket);
+Common::println("bucket $bucket policy: " . $policy);
+
+
+// Delete bucket pllicy
+$policy = $ossClient->deleteBucketPolicy($bucket);
+
+//******************************* For complete usage, see the following functions ****************************************************
+
+putBucketPolicy($ossClient, $bucket);
+getBucketPolicy($ossClient, $bucket);
+deleteBucketPolicy($ossClient, $bucket);
+
+/**
+ * Set Bucket Policy
+ *
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function putBucketPolicy($ossClient, $bucket)
+{
+	$policy = <<< BBBB
+{
+  "Version":"1",
+  "Statement":[
+  {
+    "Action":[
+    "oss:PutObject",
+    "oss:GetObject"
+  ],
+    "Effect":"Allow",
+    "Resource":["acs:oss:*:*:*/user1/*"]
+  }
+  ]
+}
+BBBB;
+	
+	try {
+		$ossClient->putBucketPolicy($bucket, $policy);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * Get Bucket Policy
+ *
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function getBucketPolicy($ossClient, $bucket)
+{
+	try {
+		$policy = $ossClient->getBucketPolicy($bucket);
+		print($policy);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * Delete Bucket Policy
+ *
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function deleteBucketPolicy($ossClient, $bucket)
+{
+	try {
+		$ossClient->deleteBucketPolicy($bucket);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}

+ 112 - 0
vendor/aliyuncs/oss-sdk-php/samples/BucketTags.php

@@ -0,0 +1,112 @@
+<?php
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+use OSS\Model\TaggingConfig;
+use OSS\Model\Tag;
+
+$ossClient = Common::getOssClient();
+if (is_null($ossClient)) exit(1);
+$bucket = Common::getBucketName();
+
+//******************************* Simple Usage****************************************************************
+
+// Set bucket tag
+$config = new TaggingConfig();
+$config->addTag(new Tag("key1", "value1"));
+$config->addTag(new Tag("key2", "value2"));
+$ossClient->putBucketTags($bucket, $config);
+
+// Get bucket tags
+$config = $ossClient->getBucketTags($bucket);
+Common::println("bucket $bucket tags: ".$config->serializeToXml());
+
+// Delete bucket tags
+
+// Delete the specified tag of the bucket.
+$tags = array();
+$tags[] = new Tag("key1", "value1");
+$tags[] = new Tag("key2", "value2");
+$ossClient->deleteBucketTags($bucket, $tags);
+
+// Delete all tags in the bucket.
+$ossClient->deleteBucketTags($bucket);
+
+//******************************* For complete usage, see the following functions ****************************************************
+
+putBucketTags($ossClient, $bucket);
+getBucketTags($ossClient, $bucket);
+deleteBucketTags($ossClient, $bucket);
+
+
+/**
+ * Create bucket tag
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function putBucketTags($ossClient, $bucket)
+{
+	try {
+		// 设置Bucket标签。
+		$config = new TaggingConfig();
+		$config->addTag(new Tag("key1", "value1"));
+		$config->addTag(new Tag("key2", "value2"));
+		$ossClient->putBucketTags($bucket, $config);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * get bucket tag
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function getBucketTags($ossClient, $bucket)
+{
+	try {
+		$config = $ossClient->getBucketTags($bucket);
+		print_r($config->getTags());
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * delete bucket tag
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function deleteBucketTags($ossClient, $bucket)
+{
+	try {
+		// Delete the specified tag of the bucket.
+		$tags = array();
+		$tags[] = new Tag("key1", "value1");
+		$tags[] = new Tag("key2", "value2");
+		$ossClient->deleteBucketTags($bucket, $tags);
+		
+		// Delete all tags in the bucket.
+		//$ossClient->deleteBucketTags($bucket);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+

+ 61 - 0
vendor/aliyuncs/oss-sdk-php/samples/BucketTransferAcceleration.php

@@ -0,0 +1,61 @@
+<?php
+
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+
+$ossClient = Common::getOssClient();
+if (is_null($ossClient)) exit(1);
+$bucket = Common::getBucketName();
+
+//******************************* Simple Usage****************************************************************
+
+// set <tran></tran>sfer acceleration
+$enabled = true; // set true to enable transfer acceleration; set false to disalbe transfer acceleration
+$ossClient->putBucketTransferAcceleration($bucket, $enabled);
+printf('putBucketTransferAcceleration SUCCESS' . "\n");
+
+
+// get transfer acceleration
+$result  = $ossClient->getBucketTransferAcceleration($bucket);
+printf('getBucketTransferAcceleration Status:%s'."\n",$result);
+
+
+//******************************* For complete usage, see the following functions ****************************************************
+putBucketTransferAcceleration($ossClient,$bucket);
+getBucketTransferAcceleration($bucket);
+
+/**
+ * @param $ossClient OssClient
+ * @param $bucket bucket_name string
+ * @param $enabled string
+ */
+function putBucketTransferAcceleration($ossClient, $bucket, $enabled)
+{
+	try{
+		$enabled = true; // set true to enable transfer acceleration; set false to disalbe transfer acceleration
+		$ossClient->putBucketTransferAcceleration($bucket,$enabled);
+		printf('putBucketTransferAcceleration SUCCESS' . "\n");
+	} catch(OssException $e) {
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * @param $ossClient OssClient
+ * @param $bucket bucket_name string
+ */
+function getBucketTransferAcceleration($ossClient, $bucket)
+{
+	try{
+		$result = $ossClient->getBucketTransferAcceleration($bucket);
+		printf('getBucketTransferAcceleration Status:%s'."\n",$result);
+	} catch(OssException $e) {
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	print(__FUNCTION__ . ": OK" . "\n");
+}

+ 235 - 0
vendor/aliyuncs/oss-sdk-php/samples/BucketVersion.php

@@ -0,0 +1,235 @@
+<?php
+
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+
+$ossClient = Common::getOssClient();
+if (is_null($ossClient)) exit(1);
+$bucket = Common::getBucketName();
+
+//******************************* Simple Usage****************************************************************
+
+//Set Bucket version control status
+//Set the storage space version control to enable version control (Enabled) or suspend version control (Suspended).
+$ossClient->putBucketVersioning($bucket, "Enabled");
+Common::println("bucket $bucket version Enabled");
+// show all object list
+$option = array(
+	OssClient::OSS_KEY_MARKER => null,
+	OssClient::OSS_VERSION_ID_MARKER => null
+);
+$bool = true;
+while ($bool) {
+	$result = $ossClient->listObjectVersions($bucket, $option);
+	## View the version information of the listed object.
+	foreach ($result->getObjectVersionList() as $key => $info) {
+		Common::println("key name: " . $info->getKey());
+		Common::println("versionid: " . $info->getVersionId());
+		Common::println("Is latest: " . $info->getIsLatest());
+	}
+	
+	## View the version information that lists the deletion flags.
+	foreach ($result->getDeleteMarkerList() as $key => $info) {
+		Common::println("del_maker key name: " . $info->getKey());
+		Common::println("del_maker versionid: " . $info->getVersionId());
+		Common::println("del_maker Is latest: " . $info->getIsLatest());
+	}
+	
+	if ($result->getIsTruncated() === 'true') {
+		$option = array(
+			OssClient::OSS_KEY_MARKER => $result->getNextKeyMarker(),
+			OssClient::OSS_VERSION_ID_MARKER => $result->getNextVersionIdMarker()
+		);
+	} else {
+		$bool = false;
+	}
+}
+
+// show the prefix object
+
+$option = array(
+	OssClient::OSS_KEY_MARKER => null,
+	OssClient::OSS_VERSION_ID_MARKER => null,
+	OssClient::OSS_PREFIX => "test"
+);
+$bool = true;
+while ($bool) {
+	$result = $ossClient->listObjectVersions($bucket, $option);
+	## View the version information of the listed object.
+	foreach ($result->getObjectVersionList() as $key => $info) {
+		Common::println("key name: " . $info->getKey());
+		Common::println("versionid: " . $info->getVersionId());
+		Common::println("Is latest: " . $info->getIsLatest());
+	}
+	
+	## View the version information that lists the deletion flags.
+	foreach ($result->getDeleteMarkerList() as $key => $info) {
+		Common::println("del_maker key name: " . $info->getKey());
+		Common::println("del_maker versionid: " . $info->getVersionId());
+		Common::println("del_maker Is latest: " . $info->getIsLatest());
+	}
+	
+	if ($result->getIsTruncated() === 'true') {
+		$option[OssClient::OSS_KEY_MARKER] = $result->getNextKeyMarker();
+		$option[OssClient::OSS_VERSION_ID_MARKER] = $result->getNextVersionIdMarker();
+	} else {
+		$bool = false;
+	}
+}
+
+// list the number of objects
+
+$option = array(
+	OssClient::OSS_KEY_MARKER => null,
+	OssClient::OSS_VERSION_ID_MARKER => null,
+	OssClient::OSS_MAX_KEYS => 200
+);
+
+$result = $ossClient->listObjectVersions($bucket, $option);
+## View the version information of the listed object.
+foreach ($result->getObjectVersionList() as $key => $info) {
+	Common::println("key name: " . $info->getKey());
+	Common::println("versionid: " . $info->getVersionId());
+	Common::println("Is latest: " . $info->getIsLatest());
+}
+
+## View the version information that lists the deletion flags.
+foreach ($result->getDeleteMarkerList() as $key => $info) {
+	Common::println("del_maker key name: " . $info->getKey());
+	Common::println("del_maker versionid: " . $info->getVersionId());
+	Common::println("del_maker Is latest: " . $info->getIsLatest());
+}
+
+
+// show root folder list
+$option = array(
+	OssClient::OSS_KEY_MARKER => null,
+	OssClient::OSS_VERSION_ID_MARKER => null,
+	OssClient::OSS_DELIMITER => "/",
+);
+$bool = true;
+while ($bool) {
+	$result = $ossClient->listObjectVersions($bucket, $option);
+	## View the version information of the listed object.
+	foreach ($result->getObjectVersionList() as $key => $info) {
+		Common::println("key name: " . $info->getKey());
+		Common::println("versionid: " . $info->getVersionId());
+		Common::println("Is latest: " . $info->getIsLatest());
+	}
+	
+	## View the version information that lists the deletion flags.
+	foreach ($result->getDeleteMarkerList() as $key => $info) {
+		Common::println("del_maker key name: " . $info->getKey());
+		Common::println("del_maker versionid: " . $info->getVersionId());
+		Common::println("del_maker Is latest: " . $info->getIsLatest());
+	}
+	
+	if ($result->getIsTruncated() === 'true') {
+		$option[OssClient::OSS_KEY_MARKER] = $result->getNextKeyMarker();
+		$option[OssClient::OSS_VERSION_ID_MARKER] = $result->getNextVersionIdMarker();
+	} else {
+		$bool = false;
+	}
+}
+
+//  Show subfolder objects list
+$option = array(
+	OssClient::OSS_KEY_MARKER => null,
+	OssClient::OSS_VERSION_ID_MARKER => null,
+	OssClient::OSS_DELIMITER => "/",
+	OssClient::OSS_PREFIX => "test/",
+);
+$bool = true;
+while ($bool) {
+	$result = $ossClient->listObjectVersions($bucket, $option);
+	## View the version information of the listed object.
+	foreach ($result->getObjectVersionList() as $key => $info) {
+		Common::println("key name: " . $info->getKey());
+		Common::println("versionid: " . $info->getVersionId());
+		Common::println("Is latest: " . $info->getIsLatest());
+	}
+	
+	## View the version information that lists the deletion flags.
+	foreach ($result->getDeleteMarkerList() as $key => $info) {
+		Common::println("del_maker key name: " . $info->getKey());
+		Common::println("del_maker versionid: " . $info->getVersionId());
+		Common::println("del_maker Is latest: " . $info->getIsLatest());
+	}
+	
+	if ($result->getIsTruncated() === 'true') {
+		$option[OssClient::OSS_KEY_MARKER] = $result->getNextKeyMarker();
+		$option[OssClient::OSS_VERSION_ID_MARKER] = $result->getNextVersionIdMarker();
+	} else {
+		$bool = false;
+	}
+}
+
+
+//******************************* For complete usage, see the following functions ****************************************************
+
+listObjectVersions($ossClient, $bucket);
+putBucketVersioning($ossClient, $bucket);
+/**
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function listObjectVersions($ossClient, $bucket)
+{
+	try {
+		$option = array(
+			OssClient::OSS_KEY_MARKER => null,
+			OssClient::OSS_VERSION_ID_MARKER => null,
+		);
+		$bool = true;
+		while ($bool) {
+			$result = $ossClient->listObjectVersions($bucket, $option);
+			## View the version information of the listed object.
+			foreach ($result->getObjectVersionList() as $key => $info) {
+				Common::println("key name: " . $info->getKey());
+				Common::println("versionid: " . $info->getVersionId());
+				Common::println("Is latest: " . $info->getIsLatest());
+			}
+			
+			## View the version information that lists the deletion flags.
+			foreach ($result->getDeleteMarkerList() as $key => $info) {
+				Common::println("del_maker key name: " . $info->getKey());
+				Common::println("del_maker versionid: " . $info->getVersionId());
+				Common::println("del_maker Is latest: " . $info->getIsLatest());
+			}
+			
+			if ($result->getIsTruncated() === 'true') {
+				$option[OssClient::OSS_KEY_MARKER] = $result->getNextKeyMarker();
+				$option[OssClient::OSS_VERSION_ID_MARKER] = $result->getNextVersionIdMarker();
+			} else {
+				$bool = false;
+			}
+		}
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * Enabled or Suspended bucket version
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function putBucketVersioning($ossClient, $bucket)
+{
+	try {
+		//Set the storage space version control to enable version control (Enabled) or suspend version control (Suspended).
+		$ossClient->putBucketVersioning($bucket, "Enabled");
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	print(__FUNCTION__ . ": OK" . "\n");
+}

+ 145 - 0
vendor/aliyuncs/oss-sdk-php/samples/BucketWorm.php

@@ -0,0 +1,145 @@
+<?php
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+
+$ossClient = Common::getOssClient();
+if (is_null($ossClient)) exit(1);
+$bucket = Common::getBucketName();
+
+//******************************* Simple Usage****************************************************************
+
+// Create a new compliance retention policy:
+// The specified object protection days are 30 days.
+$wormId = $ossClient->initiateBucketWorm($bucket, 30);
+Common::println("bucket $bucket wormId: " . $wormId.PHP_EOL);
+
+// Cancel an unlocked compliance retention policy
+$ossClient->abortBucketWorm($bucket);
+
+//Lock compliant retention policy
+$wormId = $ossClient->initiateBucketWorm($bucket, 30);
+$ossClient->completeBucketWorm($bucket, $wormId);
+
+// Get compliant retention policy
+$config = $ossClient->getBucketWorm($bucket);
+Common::println("WormId:".$config->getWormId().PHP_EOL);
+Common::println("State:". $config->getState().PHP_EOL);
+Common::println("Day:". $config->getDay().PHP_EOL);
+
+// Extend the retention days of objects
+$wormId = "<yourWormId>";
+// Extend the retention days of objects in the locked compliance retention policy to 120 days.
+$ossClient->extendBucketWorm($bucket, $wormId, 120);
+
+//******************************* For complete usage, see the following functions ****************************************************
+
+initiateBucketWorm($ossClient, $bucket);
+abortBucketWorm($ossClient, $bucket);
+completeBucketWorm($ossClient, $bucket);
+getBucketWorm($ossClient, $bucket);
+extendBucketWorm($ossClient, $bucket);
+
+/**
+ * Set Bucket Worm Ploicy
+ *
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function initiateBucketWorm($ossClient, $bucket)
+{
+	try {
+		$wormId = $ossClient->initiateBucketWorm($bucket,30);
+		print("bucket $bucket wormId: " . $wormId.PHP_EOL);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * Cancel an unlocked compliance retention policy
+ *
+ * @param OssClient $ossClient OssClient instance
+ * @param string $bucket Name of the bucket to create
+ * @return null
+ */
+function abortBucketWorm($ossClient, $bucket)
+{
+	try {
+		$ossClient->abortBucketWorm($bucket);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * Complete Bucket Worm
+ * @param $ossClient $ossClient OssClient instance
+ * @param $bucket $bucket Name of the bucket to create
+ */
+function completeBucketWorm($ossClient, $bucket)
+{
+	try {
+		$wormId = $ossClient->initiateBucketWorm($bucket, 30);
+		$ossClient->completeBucketWorm($bucket, $wormId);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * Get Bucket Worm
+ * @param $ossClient $ossClient OssClient instance
+ * @param $bucket $bucket Name of the bucket to create
+ */
+function getBucketWorm($ossClient, $bucket)
+{
+	try {
+		$config = $ossClient->getBucketWorm($bucket);
+		
+		printf("WormId:%s\n", $config->getWormId());
+		printf("State:%s\n", $config->getState());
+		printf("Day:%d\n", $config->getDay());
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * Extend the retention days of objects
+ * @param $ossClient $ossClient OssClient instance
+ * @param $bucket $bucket Name of the bucket to create
+ */
+function extendBucketWorm($ossClient, $bucket)
+{
+	$wormId = "<yourWormId>";
+	try {
+		$ossClient->ExtendBucketWorm($bucket, $wormId, 120);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}

+ 366 - 0
vendor/aliyuncs/oss-sdk-php/samples/ObjectTagging.php

@@ -0,0 +1,366 @@
+<?php
+
+require_once __DIR__ . '/Common.php';
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+use OSS\Core\OssUtil;
+use OSS\Model\TaggingConfig;
+use OSS\Model\Tag;
+
+$bucket = Common::getBucketName();
+$ossClient = Common::getOssClient();
+if (is_null($ossClient)) exit(1);
+//******************************* Simple usage ***************************************************************
+
+// Upload Object add tag
+$object = "b.file";
+$options = array(
+	OssClient::OSS_HEADERS => array(
+		'x-oss-tagging' => 'key1=value1&key2=value2&key3=value3',
+	)
+);
+$result = $ossClient->putObject($bucket, $object, __FILE__,$options);
+Common::println("b.file is created");
+Common::println("tag is:".$result['oss-requestheaders']['x-oss-tagging']);
+
+// Add object tags when uploading parts
+
+$object = "b.file";
+$file = __FILE__;
+$options = array(
+	OssClient::OSS_CHECK_MD5 => true,
+	OssClient::OSS_PART_SIZE => 1,
+	OssClient::OSS_HEADERS => array(
+		'x-oss-tagging' => 'key1=value1&key2=value2&key3=value3',
+	),
+);
+$result = $ossClient->multiuploadFile($bucket, $object, $file, $options);
+Common::println("b.file is created");
+Common::println("tag is:".$result['oss-requestheaders']['x-oss-tagging']);
+
+// get tags from object
+
+$object = "a.txt";
+$result = $ossClient->getObjectTagging($bucket,$object);
+printf($object.'tags is: '.$result->serializeToXml().PHP_EOL);
+
+
+// Add or change object tags to uploaded objects
+$config = new TaggingConfig();
+$config->addTag(new Tag("key1", "value1"));
+$config->addTag(new Tag("key2", "value2"));
+
+$ossClient->putObjectTagging($bucket, $object, $config);
+// Add object tags when uploading
+$object = "a.txt";
+$filePath = "D:\\localpath\\b.txt";
+$filePath1 = "D:\\localpath\\c.txt";
+$options = array(
+	OssClient::OSS_HEADERS => array(
+		'x-oss-tagging' => 'key1=value1&key2=value2',
+	)
+);
+$position = $ossClient->appendObject($bucket, $object,'content one',0,$options);
+printf('Content one append object Success'.PHP_EOL);
+$position = $ossClient->appendObject($bucket, $object, 'content two',$position,$options);
+printf('Content two append object Success'.PHP_EOL);
+
+// delete tags
+$object = "g.file";
+$ossClient->deleteObjectTagging($bucket, $object);
+printf($object.' tags has deleted'.PHP_EOL);
+
+// Copy a small file
+$fromBucket = $bucket;
+$fromObject = "a.file";
+$toBucket = $bucket;
+$toObject = $fromObject . '.copy';
+$options = array(
+	OssClient::OSS_HEADERS => array(
+		'x-oss-tagging-directive' => 'Replace',
+		'x-oss-tagging'=>'key1=value1&key2=value2&key3=value3',
+	));
+$ossClient->copyObject($fromBucket, $fromObject, $toBucket, $toObject, $options);
+$config = $ossClient->getObjectTagging($bucket, $toObject);
+Common::println('object tags is:'.$config->serializeToXml());
+
+// Copy a large file
+$fromBucket = $bucket;
+$fromObject = "a.file";
+$toBucket = $bucket;
+$toObject = $fromObject . '.copy';
+$options = array(
+	OssClient::OSS_HEADERS => array(
+		'x-oss-tagging'=>'key1=value1&key2=value2&key3=value3',
+	));
+
+$part_size = 256*1024*1024;
+$objectMeta = $ossClient->getObjectMeta($fromBucket, $fromObject);
+$length = $objectMeta['content-length'];
+$upload_id = $ossClient->initiateMultipartUpload($toBucket, $toObject,$options);
+$pieces = $ossClient->generateMultiuploadParts($length, $part_size);
+$response_upload_part = array();
+$copyId = 1;
+$upload_position = 0;
+foreach ($pieces as $i => $piece) {
+	$from_pos = $upload_position + (integer)$piece['seekTo'];
+	$to_pos = (integer)$piece['length'] + $from_pos - 1;
+	$up_options = array(
+		'start' => $from_pos,
+		'end' => $to_pos,
+	);
+	$response_upload_part[] = $ossClient->uploadPartCopy( $fromBucket, $fromObject, $toBucket, $toObject, $copyId, $upload_id, $up_options);
+	printf("initiateMultipartUpload, uploadPartCopy - part#{$copyId} OK\n");
+	$copyId = $copyId + 1;
+}
+$upload_parts = array();
+foreach ($response_upload_part as $i => $etag) {
+	$upload_parts[] = array(
+		'PartNumber' => ($i + 1),
+		'ETag' => $etag,
+	);
+}
+$result = $ossClient->completeMultipartUpload($toBucket, $toObject, $upload_id, $upload_parts);
+$config = $ossClient->getObjectTagging($bucket, $toObject);
+Common::println($toObject.' tags is:'.$config->serializeToXml());
+
+
+
+//******************************* For complete usage, see the following functions ****************************************************
+
+putObject($ossClient,$bucket);
+multiuploadFile($ossClient,$bucket);
+appendObject($ossClient,$bucket);
+putObjectTagging($ossClient,$bucket);
+getObjectTagging($ossClient,$bucket);
+deleteObjectTagging($ossClient,$bucket);
+copyObjectSmall($ossClient,$bucket);
+copyObjectLarge($ossClient,$bucket);
+/**
+ *  Upload Object add tag
+ * @param $ossClient OssClient
+ * @param $bucket bucket_name
+ */
+function putObject($ossClient,$bucket){
+	$object = "b.file";
+	$options = array(
+		OssClient::OSS_HEADERS => array(
+			'x-oss-tagging' => 'key1=value1&key2=value2&key3=value3',
+		));
+	try {
+		// 通过简单上传的方式上传Object。
+		$result = $ossClient->putObject($bucket, $object, __FILE__,$options);
+		Common::println("b.file is created".PHP_EOL);
+		Common::println("tag is:".$result['oss-requestheaders']['x-oss-tagging'].PHP_EOL);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * Add object tags when uploading parts
+ * @param $ossClient OssClient
+ * @param $bucket bucket_name
+ */
+function multiuploadFile($ossClient,$bucket){
+	$object = "b.file";
+	$file = __FILE__;
+	$options = array(
+		OssClient::OSS_CHECK_MD5 => true,
+		OssClient::OSS_PART_SIZE => 1,
+		OssClient::OSS_HEADERS => array(
+			'x-oss-tagging' => 'key1=value1&key2=value2&key3=value3',
+		),
+	);
+	
+	try {
+		$result = $ossClient->multiuploadFile($bucket, $object, $file, $options);
+		Common::println("b.file is created".PHP_EOL);
+		Common::println("tag is:".$result['oss-requestheaders']['x-oss-tagging'].PHP_EOL);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * Add object tags when uploading
+ * @param $ossClient OssClient
+ * @param $bucket bucket_name string
+ */
+function appendObject($ossClient,$bucket){
+	$object = "g.file";
+	$content_array = array('Hello OSS', 'Hi OSS');
+	$options = array(
+		OssClient::OSS_HEADERS => array(
+			'x-oss-tagging' => 'key1=value1&key2=value2',
+		));
+	
+	try {
+		$position = $ossClient->appendObject($bucket, $object, $content_array[0], 0, $options);
+		printf($content_array[0].' append object Success'.PHP_EOL);
+		$position = $ossClient->appendObject($bucket, $object, $content_array[1], $position);
+		printf($content_array[1].' append object Success'.PHP_EOL);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * @param $ossClient OssClient
+ * @param $bucket bucket_name string
+ * @throws OssException
+ */
+function putObjectTagging($ossClient,$bucket){
+	$object = "g.file";
+	$config = new TaggingConfig();
+	$config->addTag(new Tag("key1", "value1"));
+	$config->addTag(new Tag("key2", "value2"));
+	
+	try {
+		$ossClient->putObjectTagging($bucket, $object, $config);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * get object tags
+ * @param $ossClient OssClient
+ * @param $bucket bucket_name string
+ */
+function getObjectTagging($ossClient,$bucket){
+	$object = "g.file";
+	try {
+		$config = $ossClient->getObjectTagging($bucket, $object);
+		printf($object." tags is:".$config->serializeToXml().PHP_EOL);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+
+/**
+ * get object tags
+ * @param $ossClient OssClient
+ * @param $bucket bucket_name string
+ */
+function deleteObjectTagging($ossClient,$bucket){
+	$object = "g.file";
+	try {
+		$ossClient->deleteObjectTagging($bucket, $object);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * Copy small files
+ * @param $ossClient OssClient
+ * @param $bucket bucket_name string
+ */
+function copyObjectSmall($ossClient,$bucket){
+	$fromBucket = $bucket;
+	$fromObject = "a.file";
+	$toBucket = $bucket;
+	$toObject = $fromObject . '.copy';
+	$options = array(
+		OssClient::OSS_HEADERS => array(
+			'x-oss-tagging-directive' => 'Replace',
+			'x-oss-tagging'=>'key1=value1&key2=value2&key3=value3',
+		));
+	
+	try {
+		$ossClient->copyObject($fromBucket, $fromObject, $toBucket, $toObject, $options);
+	} catch (OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+	}
+	
+	$config = $ossClient->getObjectTagging($bucket, $toObject);
+	Common::println('object tags is:'.$config->serializeToXml());
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+
+/**
+ * Copy a large file
+ * @param $ossClient OssClient
+ * @param $bucket bucket_name string
+ */
+function copyObjectLarge($ossClient,$bucket){
+	$fromBucket = $bucket;
+	$fromObject = "a.file";
+	$toBucket = $bucket;
+	$toObject = $fromObject . '.copy';
+	$options = array(
+		OssClient::OSS_HEADERS => array(
+			'x-oss-tagging'=>'key1=value1&key2=value2&key3=value3',
+		));
+	
+	$part_size = 256*1024*1024;
+	try{
+		$objectMeta = $ossClient->getObjectMeta($fromBucket, $fromObject);
+		$length = $objectMeta['content-length'];
+		$upload_id = $ossClient->initiateMultipartUpload($toBucket, $toObject,$options);
+		$pieces = $ossClient->generateMultiuploadParts($length, $part_size);
+		$response_upload_part = array();
+		$copyId = 1;
+		$upload_position = 0;
+		foreach ($pieces as $i => $piece) {
+			$from_pos = $upload_position + (integer)$piece['seekTo'];
+			$to_pos = (integer)$piece['length'] + $from_pos - 1;
+			$up_options = array(
+				'start' => $from_pos,
+				'end' => $to_pos,
+			);
+			$response_upload_part[] = $ossClient->uploadPartCopy( $fromBucket, $fromObject, $toBucket, $toObject, $copyId, $upload_id, $up_options);
+			printf("initiateMultipartUpload, uploadPartCopy - part#{$copyId} OK\n");
+			$copyId = $copyId + 1;
+		}
+		$upload_parts = array();
+		foreach ($response_upload_part as $i => $etag) {
+			$upload_parts[] = array(
+				'PartNumber' => ($i + 1),
+				'ETag' => $etag,
+			);
+		}
+		$result = $ossClient->completeMultipartUpload($toBucket, $toObject, $upload_id, $upload_parts);
+		printf('copy success'. "\n");
+	} catch(OssException $e) {
+		printf(__FUNCTION__ . ": FAILED\n");
+		printf($e->getMessage() . "\n");
+		return;
+		
+		
+	}
+	$config = $ossClient->getObjectTagging($bucket, $toObject);
+	Common::println($toObject.' tags is:'.$config->serializeToXml());
+	print(__FUNCTION__ . ": OK" . "\n");
+}
+

+ 105 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Model/CnameTokenInfo.php

@@ -0,0 +1,105 @@
+<?php
+
+namespace OSS\Model;
+
+
+/**
+ * Cname token info class.
+ *
+ * Class CnameTokenInfo
+ * @package OSS\Model
+ */
+class CnameTokenInfo
+{
+    /**
+     * Get bucket name
+     *
+     * @return string
+     */
+    public function getBucket()
+    {
+        return $this->bucket;
+    }
+
+    /**
+     * Get cname
+     *
+     * @return string
+     */
+    public function getCname()
+    {
+        return $this->cname;
+    }
+
+    /**
+     * Get token.
+     *
+     * @return string
+     */
+    public function getToken()
+    {
+        return $this->token;
+    }
+
+    /**
+     * Get expireTime.
+     *
+     * @return string
+     */
+    public function getExpireTime()
+    {
+        return $this->expireTime;
+    }
+
+    /**
+     * Parse cname token from the xml.
+     *
+     * @param string $strXml
+     * @throws OssException
+     * @return null
+     */
+    public function parseFromXml($strXml)
+    {
+        $xml = simplexml_load_string($strXml);
+        if (isset($xml->Bucket) ) {
+            $this->bucket = strval($xml->Bucket);
+        }
+        if (isset($xml->Cname) ) {
+            $this->cname = strval($xml->Cname);
+        }
+        if (isset($xml->Token) ) {
+            $this->token = strval($xml->Token);
+        }
+        if (isset($xml->ExpireTime) ) {
+            $this->expireTime = strval($xml->ExpireTime);
+        }
+    }
+    
+    /**
+     * bucket name
+     *
+     * @var string
+     */
+    private $bucket;
+    /**
+     * cname
+     *
+     * @var string
+     */
+    private $cname;
+
+    /**
+     * token
+     *
+     * @var string
+     */
+    private $token;
+
+    /**
+     * expire time
+     *
+     * @var string
+     */
+    private $expireTime;
+
+}

+ 147 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Model/ObjectListInfoV2.php

@@ -0,0 +1,147 @@
+<?php
+
+namespace OSS\Model;
+
+/**
+ * Class ObjectListInfoV2
+ *
+ * The class of return value of ListObjectsV2
+ *
+ * @package OSS\Model
+ */
+class ObjectListInfoV2
+{
+    /**
+     * ObjectListInfoV2 constructor.
+     *
+     * @param string $bucketName
+     * @param string $prefix
+     * @param int $maxKeys
+     * @param string $delimiter
+     * @param null $isTruncated
+     * @param array $objectList
+     * @param array $prefixList
+     * @param string $continuationToken
+     * @param string $nextContinuationToken
+     * @param string $startAfter
+     * @param int $keyCount
+     */
+    public function __construct($bucketName, $prefix, $maxKeys, $delimiter, $isTruncated, array $objectList, array $prefixList, $continuationToken, $nextContinuationToken, $startAfter, $keyCount)
+    {
+        $this->bucketName = $bucketName;
+        $this->prefix = $prefix;
+        $this->maxKeys = $maxKeys;
+        $this->delimiter = $delimiter;
+        $this->isTruncated = $isTruncated;
+        $this->objectList = $objectList;
+        $this->prefixList = $prefixList;
+        $this->continuationToken = $continuationToken;
+        $this->nextContinuationToken = $nextContinuationToken;
+        $this->startAfter = $startAfter;
+        $this->keyCount = $keyCount;
+    }
+
+    /**
+     * @return string
+     */
+    public function getBucketName()
+    {
+        return $this->bucketName;
+    }
+
+    /**
+     * @return string
+     */
+    public function getPrefix()
+    {
+        return $this->prefix;
+    }
+
+    /**
+     * @return int
+     */
+    public function getMaxKeys()
+    {
+        return $this->maxKeys;
+    }
+
+    /**
+     * @return string
+     */
+    public function getDelimiter()
+    {
+        return $this->delimiter;
+    }
+
+    /**
+     * @return mixed
+     */
+    public function getIsTruncated()
+    {
+        return $this->isTruncated;
+    }
+
+    /**
+     * Get the ObjectInfo list.
+     *
+     * @return ObjectInfo[]
+     */
+    public function getObjectList()
+    {
+        return $this->objectList;
+    }
+
+    /**
+     * Get the PrefixInfo list
+     *
+     * @return PrefixInfo[]
+     */
+    public function getPrefixList()
+    {
+        return $this->prefixList;
+    }
+
+    /**
+     * @return string
+     */
+    public function getContinuationToken()
+    {
+        return $this->continuationToken;
+    }
+    
+    /**
+     * @return string
+     */
+    public function getNextContinuationToken()
+    {
+        return $this->nextContinuationToken;
+    }
+    
+    /**
+     * @return string
+     */
+    public function getStartAfter()
+    {
+        return $this->startAfter;
+    }
+
+    /**
+     * @return int
+     */
+    public function getKeyCount()
+    {
+        return $this->keyCount;
+    }
+
+    private $bucketName = "";
+    private $prefix = "";
+    private $maxKeys = 0;
+    private $delimiter = "";
+    private $isTruncated = null;
+    private $objectList = array();
+    private $prefixList = array();
+    private $nextContinuationToken = "";
+    private $continuationToken = "";
+    private $startAfter = "";
+    private $keyCount = 0;
+}

+ 73 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Model/TransferAccelerationConfig.php

@@ -0,0 +1,73 @@
+<?php
+
+namespace OSS\Model;
+
+use OSS\Core\OssException;
+
+/**
+ * Class TransferAccelerationConfig
+ * @package OSS\Model
+ */
+class TransferAccelerationConfig implements XmlConfig
+{
+	/**
+	 * Parse TransferAccelerationConfig from the xml.
+	 * @param string $strXml
+	 * @throws OssException
+	 * @return null
+	 */
+	public function parseFromXml($strXml)
+	{
+		$xml = simplexml_load_string($strXml);
+		if (isset($xml->Enabled)) {
+			$this->enabled = (strval($xml->Enabled) === 'TRUE' || strval($xml->Enabled) === 'true') ? true : false;
+		}
+	}
+	
+	/**
+	 * Serialize the object into xml string.
+	 *
+	 * @return string
+	 */
+	public function serializeToXml()
+	{
+		$xml = new \SimpleXMLElement('<?xml version="1.0" encoding="utf-8"?><TransferAccelerationConfiguration></TransferAccelerationConfiguration>');
+		if (isset($this->enabled)) {
+			if($this->enabled === true){
+				$xml->addChild('Enabled','true');
+			} else {
+				$xml->addChild('Enabled','false');
+			}
+		}
+		return $xml->asXML();
+	}
+	
+	public function __toString()
+	{
+		return $this->serializeToXml();
+	}
+	
+	
+	/**
+	 * @return bool
+	 */
+	public function getEnabled()
+	{
+		return $this->enabled;
+	}
+	
+    /**
+     * @param boolean enabled
+     */
+    public function setEnabled($enabled)
+    {
+        $this->enabled = $enabled;
+    }
+
+	/**
+	 * @var $enabled boolean
+	 */
+	private $enabled = false;
+}
+
+

+ 19 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Result/CreateBucketCnameTokenResult.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace OSS\Result;
+
+use OSS\Model\CnameTokenInfo;
+
+class CreateBucketCnameTokenResult extends Result
+{
+    /**
+     * @return CnameConfig
+     */
+    protected function parseDataFromResponse()
+    {
+        $content = $this->rawResponse->body;
+        $info = new CnameTokenInfo();
+        $info->parseFromXml($content);
+        return $info;
+    }
+}

+ 19 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Result/GetBucketCnameTokenResult.php

@@ -0,0 +1,19 @@
+<?php
+
+namespace OSS\Result;
+
+use OSS\Model\CnameTokenInfo;
+
+class GetBucketCnameTokenResult extends Result
+{
+    /**
+     * @return CnameConfig
+     */
+    protected function parseDataFromResponse()
+    {
+        $content = $this->rawResponse->body;
+        $info = new CnameTokenInfo();
+        $info->parseFromXml($content);
+        return $info;
+    }
+}

+ 22 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Result/GetBucketTransferAccelerationResult.php

@@ -0,0 +1,22 @@
+<?php
+
+namespace OSS\Result;
+use OSS\Model\TransferAccelerationConfig;
+
+/**
+ * Class GetBucketTransferAccelerationResult
+ * @package OSS\Result
+ */
+class GetBucketTransferAccelerationResult extends Result
+{
+	/**
+	 * @return bool
+	 */
+	protected function parseDataFromResponse()
+	{
+		$content = $this->rawResponse->body;
+		$config = new TransferAccelerationConfig();
+		$config->parseFromXml($content);
+		return $config->getEnabled();
+	}
+}

+ 72 - 0
vendor/aliyuncs/oss-sdk-php/src/OSS/Result/ListObjectsV2Result.php

@@ -0,0 +1,72 @@
+<?php
+
+namespace OSS\Result;
+
+use OSS\Core\OssUtil;
+use OSS\Model\ObjectInfo;
+use OSS\Model\ObjectListInfoV2;
+use OSS\Model\PrefixInfo;
+
+/**
+ * Class ListObjectsV2Result
+ * @package OSS\Result
+ */
+class ListObjectsV2Result extends Result
+{
+    /**
+     * Parse the xml data returned by the ListObjectsV2 interface
+     *
+     * return ObjectListInfoV2
+     */
+    protected function parseDataFromResponse()
+    {
+        $xml = new \SimpleXMLElement($this->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);
+        $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) : "";
+        $continuationToken = isset($xml->ContinuationToken) ? strval($xml->ContinuationToken) : "";
+        $nextContinuationToken = isset($xml->NextContinuationToken) ? strval($xml->NextContinuationToken) : "";
+        $startAfter = isset($xml->StartAfter) ? strval($xml->StartAfter) : "";
+        $startAfter =  OssUtil::decodeKey($startAfter, $encodingType);
+        $keyCount = isset($xml->KeyCount) ? intval($xml->KeyCount) : 0;
+        return new ObjectListInfoV2($bucketName, $prefix, $maxKeys, $delimiter, $isTruncated, $objectList, $prefixList, $continuationToken, $nextContinuationToken, $startAfter, $keyCount);
+    }
+
+    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) ? strval($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;
+    }
+}

+ 31 - 0
vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/CnameTokenInfoTest.php

@@ -0,0 +1,31 @@
+<?php
+
+namespace OSS\Tests;
+
+
+use OSS\Model\CnameTokenInfo;
+use OSS\Core\OssException;
+
+class CnameTokenInfoTest extends \PHPUnit\Framework\TestCase
+{
+    private $xml1 = <<<BBBB
+<?xml version="1.0" encoding="utf-8"?>
+<CnameToken>
+  <Bucket>bucket</Bucket>
+  <Cname>www.foo.com</Cname>
+  <Token>1234</Token>
+  <ExpireTime>20150101</ExpireTime>
+</CnameToken>
+BBBB;
+
+    public function testFromXml()
+    {
+        $info = new CnameTokenInfo();
+        $info->parseFromXml($this->xml1);
+
+        $this->assertEquals('bucket', $info->getBucket());
+        $this->assertEquals('www.foo.com', $info->getCname());
+        $this->assertEquals('1234', $info->getToken());
+        $this->assertEquals('20150101', $info->getExpireTime());
+    }
+}

+ 61 - 0
vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/GetBucketTransferAccelerationResultTest.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace OSS\Tests;
+
+use OSS\Result\GetBucketTransferAccelerationResult;
+use OSS\Http\ResponseCore;
+
+class GetBucketTransferAccelerationResultTest extends \PHPUnit\Framework\TestCase
+{
+
+    private $validXml = <<<BBBB
+<TransferAccelerationConfiguration>
+<Enabled>true</Enabled>
+</TransferAccelerationConfiguration>
+BBBB;
+    private $validXml1 = <<<BBBB
+<TransferAccelerationConfiguration>
+<Enabled>false</Enabled>
+</TransferAccelerationConfiguration>
+BBBB;
+
+    private $invalidXml2 = <<<BBBB
+<?xml version="1.0" ?>
+<TransferAccelerationConfiguration>
+</TransferAccelerationConfiguration>
+BBBB;
+
+    public function testParseValidXml()
+    {
+        $response = new ResponseCore(array(), $this->validXml, 200);
+        $result = new GetBucketTransferAccelerationResult($response);
+        $this->assertTrue($result->isOK());
+        $this->assertNotNull($result->getData());
+        $this->assertNotNull($result->getRawResponse());
+        $enabled = $result->getData();
+        $this->assertEquals(true, $enabled);
+    }
+
+    public function testParseValidXml1()
+    {
+        $response = new ResponseCore(array(), $this->validXml1, 200);
+        $result = new GetBucketTransferAccelerationResult($response);
+        $this->assertTrue($result->isOK());
+        $this->assertNotNull($result->getData());
+        $this->assertNotNull($result->getRawResponse());
+        $enabled = $result->getData();
+        $this->assertEquals(false, $enabled);
+    }
+
+    public function testParseInvalidXml2()
+    {
+        $response = new ResponseCore(array(), $this->invalidXml2, 200);
+        $result = new GetBucketTransferAccelerationResult($response);
+        $this->assertTrue($result->isOK());
+        $this->assertNotNull($result->getData());
+        $this->assertNotNull($result->getRawResponse());
+        $this->assertNotNull($result->getRawResponse()->body);
+        $enabled = $result->getData();
+        $this->assertEquals(false, $enabled);
+    }
+}

+ 154 - 0
vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/ListObjectsV2ResultTest.php

@@ -0,0 +1,154 @@
+<?php
+
+namespace OSS\Tests;
+
+
+use OSS\Result\ListObjectsV2Result;
+use OSS\Http\ResponseCore;
+
+class ListObjectsV2ResultTest extends \PHPUnit\Framework\TestCase
+{
+
+    private $validXml1 = <<<BBBB
+<?xml version="1.0" encoding="UTF-8"?>
+<ListBucketResult>
+  <Name>testbucket-hf</Name>
+  <Prefix></Prefix>
+  <StartAfter></StartAfter>
+  <MaxKeys>1000</MaxKeys>
+  <Delimiter>/</Delimiter>
+  <IsTruncated>false</IsTruncated>
+  <CommonPrefixes>
+    <Prefix>oss-php-sdk-test/</Prefix>
+  </CommonPrefixes>
+  <CommonPrefixes>
+    <Prefix>test/</Prefix>
+  </CommonPrefixes>
+</ListBucketResult>
+BBBB;
+
+    private $validXml2 = <<<BBBB
+<?xml version="1.0" encoding="UTF-8"?>
+<ListBucketResult>
+  <Name>testbucket-hf</Name>
+  <Prefix>oss-php-sdk-test/</Prefix>
+  <StartAfter>xx</StartAfter>
+  <MaxKeys>1000</MaxKeys>
+  <Delimiter>/</Delimiter>
+  <IsTruncated>false</IsTruncated>
+  <Contents>
+    <Key>oss-php-sdk-test/upload-test-object-name.txt</Key>
+    <LastModified>2015-11-18T03:36:00.000Z</LastModified>
+    <ETag>"89B9E567E7EB8815F2F7D41851F9A2CD"</ETag>
+    <Type>Normal</Type>
+    <Size>13115</Size>
+    <StorageClass>Standard</StorageClass>
+  </Contents>
+  <KeyCount>1</KeyCount>
+</ListBucketResult>
+BBBB;
+
+    private $validXmlWithEncodedKey = <<<BBBB
+<?xml version="1.0" encoding="UTF-8"?>
+<ListBucketResult>
+  <Name>testbucket-hf</Name>
+  <EncodingType>url</EncodingType>
+  <Prefix>php%2Fprefix</Prefix>
+  <StartAfter>php%2Fmarker</StartAfter>
+  <ContinuationToken>1gJiYw--</ContinuationToken>
+  <NextContinuationToken>CgJiYw--</NextContinuationToken>
+  <MaxKeys>1000</MaxKeys>
+  <Delimiter>%2F</Delimiter>
+  <IsTruncated>true</IsTruncated>
+  <Contents>
+    <Key>php/a%2Bb</Key>
+    <LastModified>2015-11-18T03:36:00.000Z</LastModified>
+    <ETag>"89B9E567E7EB8815F2F7D41851F9A2CD"</ETag>
+    <Type>Normal</Type>
+    <Size>13115</Size>
+    <StorageClass>Standard</StorageClass>
+    <Owner>
+      <ID>cname_user</ID>
+      <DisplayName>cname_user</DisplayName>
+    </Owner>
+  </Contents>
+  <KeyCount>1</KeyCount>
+</ListBucketResult>
+BBBB;
+
+    public function testParseValidXml1()
+    {
+        $response = new ResponseCore(array(), $this->validXml1, 200);
+        $result = new ListObjectsV2Result($response);
+        $this->assertTrue($result->isOK());
+        $this->assertNotNull($result->getData());
+        $this->assertNotNull($result->getRawResponse());
+        $objectListInfo = $result->getData();
+        $this->assertEquals(2, count($objectListInfo->getPrefixList()));
+        $this->assertEquals(0, count($objectListInfo->getObjectList()));
+        $this->assertEquals('testbucket-hf', $objectListInfo->getBucketName());
+        $this->assertEquals('', $objectListInfo->getPrefix());
+        $this->assertEquals('', $objectListInfo->getStartAfter());
+        $this->assertEquals(1000, $objectListInfo->getMaxKeys());
+        $this->assertEquals('/', $objectListInfo->getDelimiter());
+        $this->assertEquals('false', $objectListInfo->getIsTruncated());
+        $this->assertEquals(0, $objectListInfo->getKeyCount());
+        $prefixes = $objectListInfo->getPrefixList();
+        $this->assertEquals('oss-php-sdk-test/', $prefixes[0]->getPrefix());
+        $this->assertEquals('test/', $prefixes[1]->getPrefix());
+    }
+
+    public function testParseValidXml2()
+    {
+        $response = new ResponseCore(array(), $this->validXml2, 200);
+        $result = new ListObjectsV2Result($response);
+        $this->assertTrue($result->isOK());
+        $this->assertNotNull($result->getData());
+        $this->assertNotNull($result->getRawResponse());
+        $objectListInfo = $result->getData();
+        $this->assertEquals(0, count($objectListInfo->getPrefixList()));
+        $this->assertEquals(1, count($objectListInfo->getObjectList()));
+        $this->assertEquals('testbucket-hf', $objectListInfo->getBucketName());
+        $this->assertEquals('oss-php-sdk-test/', $objectListInfo->getPrefix());
+        $this->assertEquals('xx', $objectListInfo->getStartAfter());
+        $this->assertEquals(1000, $objectListInfo->getMaxKeys());
+        $this->assertEquals('/', $objectListInfo->getDelimiter());
+        $this->assertEquals('false', $objectListInfo->getIsTruncated());
+        $this->assertEquals(1, $objectListInfo->getKeyCount());
+        $objects = $objectListInfo->getObjectList();
+        $this->assertEquals('oss-php-sdk-test/upload-test-object-name.txt', $objects[0]->getKey());
+        $this->assertEquals('2015-11-18T03:36:00.000Z', $objects[0]->getLastModified());
+        $this->assertEquals('"89B9E567E7EB8815F2F7D41851F9A2CD"', $objects[0]->getETag());
+        $this->assertEquals('Normal', $objects[0]->getType());
+        $this->assertEquals(13115, $objects[0]->getSize());
+        $this->assertEquals('Standard', $objects[0]->getStorageClass());
+    }
+
+    public function testParseValidXmlWithEncodedKey()
+    {
+        $response = new ResponseCore(array(), $this->validXmlWithEncodedKey, 200);
+        $result = new ListObjectsV2Result($response);
+        $this->assertTrue($result->isOK());
+        $this->assertNotNull($result->getData());
+        $this->assertNotNull($result->getRawResponse());
+        $objectListInfo = $result->getData();
+        $this->assertEquals(0, count($objectListInfo->getPrefixList()));
+        $this->assertEquals(1, count($objectListInfo->getObjectList()));
+        $this->assertEquals('testbucket-hf', $objectListInfo->getBucketName());
+        $this->assertEquals('php/prefix', $objectListInfo->getPrefix());
+        $this->assertEquals('php/marker', $objectListInfo->getStartAfter());
+        $this->assertEquals('CgJiYw--', $objectListInfo->getNextContinuationToken());
+        $this->assertEquals('1gJiYw--', $objectListInfo->getContinuationToken());
+        $this->assertEquals(1000, $objectListInfo->getMaxKeys());
+        $this->assertEquals('/', $objectListInfo->getDelimiter());
+        $this->assertEquals('true', $objectListInfo->getIsTruncated());
+        $this->assertEquals(1, $objectListInfo->getKeyCount());
+        $objects = $objectListInfo->getObjectList();
+        $this->assertEquals('php/a+b', $objects[0]->getKey());
+        $this->assertEquals('2015-11-18T03:36:00.000Z', $objects[0]->getLastModified());
+        $this->assertEquals('"89B9E567E7EB8815F2F7D41851F9A2CD"', $objects[0]->getETag());
+        $this->assertEquals('Normal', $objects[0]->getType());
+        $this->assertEquals(13115, $objects[0]->getSize());
+        $this->assertEquals('Standard', $objects[0]->getStorageClass());
+    }
+}

+ 61 - 0
vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketCnameTest.php

@@ -0,0 +1,61 @@
+<?php
+
+namespace OSS\Tests;
+
+use OSS\OssClient;
+use OSS\Core\OssException;
+use OSS\Model\CnameConfig;
+use OSS\Model\CnameTokenInfo;
+
+require_once __DIR__ . DIRECTORY_SEPARATOR . 'TestOssClientBase.php';
+
+
+class OssClientBucketCnameTest extends TestOssClientBase
+{
+    public function testBucketCname()
+    {
+        $bucketName = $this->bucket . '-cname';
+        $client = new OssClient(
+            getenv('OSS_ACCESS_KEY_ID'),
+            getenv('OSS_ACCESS_KEY_SECRET'),
+            "oss-ap-southeast-2.aliyuncs.com", false);
+
+        $client->createBucket($bucketName);
+
+        try {
+            $info1 = $client->createBucketCnameToken($bucketName, "www.example.com");
+            $this->assertEquals("www.example.com", $info1->getCname());
+            $this->assertEquals($bucketName, $info1->getBucket());
+        } catch (OssException $e) {
+            $this->assertTrue(false);
+        }
+
+        try {
+            $info2 = $client->getBucketCnameToken($bucketName, "www.example.com");
+            $this->assertEquals("www.example.com", $info2->getCname());
+            $this->assertEquals($bucketName, $info2->getBucket());
+        } catch (OssException $e) {
+            $this->assertTrue(false);
+        }
+
+        try {
+            $result = $client->addBucketCname($bucketName, "www.example.com");
+        } catch (OssException $e) {
+            $this->assertEquals('NeedVerifyDomainOwnership', $e->getErrorCode());
+        }
+
+        try {
+            $config = $client->getBucketCname($bucketName);
+        } catch (OssException $e) {
+            $this->assertTrue(false);
+        }
+
+        try {
+            $result = $client->deleteBucketCname($bucketName, "www.example.com");
+        } catch (OssException $e) {
+            $this->assertTrue(false);
+        }
+
+        $client->deleteBucket($bucketName);
+    }
+}

+ 40 - 0
vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientBucketTransferAccelerationTest.php

@@ -0,0 +1,40 @@
+<?php
+
+namespace OSS\Tests;
+
+use OSS\Core\OssException;
+
+require_once __DIR__ . DIRECTORY_SEPARATOR . 'TestOssClientBase.php';
+
+
+class OssClientBucketTransferAccelerationTest extends TestOssClientBase
+{
+    public function testBucket()
+    {
+        try {
+            Common::waitMetaSync();
+            $status = $this->ossClient->getBucketTransferAcceleration($this->bucket);
+            $this->assertTrue(false);
+        } catch (OssException $e) {
+            $this->assertEquals("NoSuchTransferAccelerationConfiguration", $e->getErrorCode());
+        }
+
+        try {
+            $this->ossClient->putBucketTransferAcceleration($this->bucket, true);
+            Common::waitMetaSync();
+            $status = $this->ossClient->getBucketTransferAcceleration($this->bucket);
+            $this->assertEquals(true, $status);
+        } catch (OssException $e) {
+            $this->assertTrue(false);
+        }
+
+        try {
+            $this->ossClient->putBucketTransferAcceleration($this->bucket, false);
+            Common::waitMetaSync();
+            $status = $this->ossClient->getBucketTransferAcceleration($this->bucket);
+            $this->assertEquals(false, $status);
+        } catch (OssException $e) {
+            $this->assertTrue(false);
+        }
+    }
+}

+ 175 - 0
vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/OssClientListObjectsV2Test.php

@@ -0,0 +1,175 @@
+<?php
+
+namespace OSS\Tests;
+
+use OSS\Core\OssException;
+use OSS\OssClient;
+
+require_once __DIR__ . DIRECTORY_SEPARATOR . 'TestOssClientBase.php';
+
+
+class OssClientListObjectsV2Test extends TestOssClientBase
+{
+    protected function setUp(): void
+    {
+        parent::setUp();
+        //folder
+        for ($i = 0; $i < 12; $i++) {
+            $key = 'folder/'. sprintf("%02d",$i);
+            $this->ossClient->putObject($this->bucket, $key, "content");
+        }
+        //test
+        for ($i = 0; $i < 8; $i++) {
+            $key = 'test/'. sprintf("%02d",$i);
+            $this->ossClient->putObject($this->bucket, $key, "content");
+        }
+        //work
+        for ($i = 0; $i < 5; $i++) {
+            $key = 'work/'. sprintf("%02d",$i);
+            $this->ossClient->putObject($this->bucket, $key, "content");
+        }
+        //sub++
+        for ($i = 0; $i < 3; $i++) {
+            $key = 'sub++/'. sprintf("%02d",$i);
+            $this->ossClient->putObject($this->bucket, $key, "content");
+        }
+
+        //file++
+        for ($i = 0; $i < 2; $i++) {
+            $key = 'file++'. sprintf("%02d",$i);
+            $this->ossClient->putObject($this->bucket, $key, "content");
+        }
+
+    }
+
+    protected function tearDown(): void
+    {
+        parent::tearDown();
+    }
+    public function testListObjectsDefault()
+    {
+        try {
+            $listObjectInfo = $this->ossClient->listObjectsV2($this->bucket);
+            $objectList = $listObjectInfo->getObjectList();
+            $prefixList = $listObjectInfo->getPrefixList();
+            $this->assertNotNull($objectList);
+            $this->assertNotNull($prefixList);
+            $this->assertTrue(is_array($objectList));
+            $this->assertTrue(is_array($prefixList));
+            $this->assertEquals((2), count($objectList));
+            $this->assertEquals(4, count($prefixList));
+
+            $this->assertEquals('file++00', $objectList[0]->getKey());
+            $this->assertEquals('file++01', $objectList[1]->getKey());
+
+            $this->assertEquals('folder/', $prefixList[0]->getPrefix());
+            $this->assertEquals('sub++/', $prefixList[1]->getPrefix());
+            $this->assertEquals('test/', $prefixList[2]->getPrefix());
+            $this->assertEquals('work/', $prefixList[3]->getPrefix());
+
+        } catch (OssException $e) {
+            $this->assertTrue(false);
+        }
+    }
+
+
+    public function testListObjectsWithPrefix()
+    {
+        /**
+         * List the files in your bucket.
+         */
+        $prefix = 'folder/';
+        $delimiter = '';
+        $maxkeys = 1000;
+        $options = array(
+            'delimiter' => $delimiter,
+            'prefix' => $prefix,
+            'max-keys' => $maxkeys,
+        );
+
+        try {
+            $listObjectInfo = $this->ossClient->listObjectsV2($this->bucket, $options);
+            $objectList = $listObjectInfo->getObjectList();
+            $prefixList = $listObjectInfo->getPrefixList();
+            $this->assertNotNull($objectList);
+            $this->assertNotNull($prefixList);
+            $this->assertTrue(is_array($objectList));
+            $this->assertTrue(is_array($prefixList));
+            $this->assertEquals(12, count($objectList));
+            $this->assertEquals(0, count($prefixList));
+
+            $this->assertEquals('folder/00', $objectList[0]->getKey());
+            $this->assertEquals('folder/01', $objectList[1]->getKey());
+            $this->assertEquals('folder/11', $objectList[11]->getKey());
+
+        } catch (OssException $e) {
+            $this->assertTrue(false);
+        }
+    }
+
+
+    public function testListObjectsWithMaxKeysAndMarker()
+    {
+        $count = 0;
+        $options = array(
+            'delimiter' => '',
+            'max-keys' => 2,
+        );
+
+        while (true) {
+            try {
+
+                $listObjectInfo = $this->ossClient->listObjectsV2($this->bucket, $options);
+            } catch (OssException $e) {
+                $this->assertTrue(false);
+            }
+            $options[OssClient::OSS_CONTINUATION_TOKEN] = $listObjectInfo->getNextContinuationToken();
+            $listObject = $listObjectInfo->getObjectList();
+            $count += count($listObject);
+            $this->assertEquals(2, count($listObject));
+            if ($listObjectInfo->getIsTruncated() !== "true") {
+                break;
+            }
+        }
+        $this->assertEquals(12 + 8 + 5 + 3 + 2, $count);
+    }
+
+
+    public function testListObjectsWithStartAfter()
+    {
+        $count = 0;
+        $options = array(
+            'delimiter' => '',
+            'start-after' => 'folder/11',
+            'max-keys' => 1,
+        );
+        while (true) {
+            try {
+                $listObjectInfo = $this->ossClient->listObjectsV2($this->bucket, $options);
+            } catch (OssException $e) {
+                $this->assertTrue(false);
+            }
+            $options[OssClient::OSS_CONTINUATION_TOKEN] = $listObjectInfo->getNextContinuationToken();
+            $listObject = $listObjectInfo->getObjectList();
+            $count += count($listObject);
+            $this->assertEquals(1, count($listObject));
+            if ($listObjectInfo->getIsTruncated() !== "true") {
+                break;
+            }
+        }
+        $this->assertEquals(8 + 5 + 3, $count);
+        $options2 = array(
+            'delimiter' => '',
+            'start-after' => 'folder/11',
+            'max-keys' => 5,
+        );
+        try {
+            $listObjectInfo = $this->ossClient->listObjectsV2($this->bucket, $options2);
+        } catch (OssException $e) {
+            $this->assertTrue(false);
+        }
+        $listObject = $listObjectInfo->getObjectList();
+        $this->assertEquals(5, count($listObject));
+        $this->assertEquals("true", $listObjectInfo->getIsTruncated());
+    }
+}

+ 56 - 0
vendor/aliyuncs/oss-sdk-php/tests/OSS/Tests/TransferAccelerationConfigTest.php

@@ -0,0 +1,56 @@
+<?php
+
+namespace OSS\Tests;
+
+use OSS\Model\TransferAccelerationConfig;
+
+class TransferAccelerationConfigTest extends \PHPUnit\Framework\TestCase
+{
+
+    private $validXml = <<<BBBB
+<?xml version="1.0" encoding="utf-8"?>
+<TransferAccelerationConfiguration>
+<Enabled>true</Enabled>
+</TransferAccelerationConfiguration>
+BBBB;
+    private $validXml1 = <<<BBBB
+<?xml version="1.0" encoding="utf-8"?>
+<TransferAccelerationConfiguration>
+<Enabled>false</Enabled>
+</TransferAccelerationConfiguration>
+BBBB;
+
+    private $invalidXml1 = <<<BBBB
+<?xml version="1.0" encoding="utf-8"?>
+<TransferAccelerationConfiguration>
+</TransferAccelerationConfiguration>
+BBBB;
+
+    public function testParseValidXml()
+    {
+        $transferConfig = new TransferAccelerationConfig();
+        $transferConfig->parseFromXml($this->validXml);
+        $this->assertEquals($this->cleanXml($this->validXml), $this->cleanXml(strval($transferConfig)));
+        $this->assertEquals(true,$transferConfig->getEnabled());
+    }
+
+    public function testValidXml1()
+    {
+        $transferConfig = new TransferAccelerationConfig();
+        $transferConfig->parseFromXml($this->validXml1);
+        $this->assertEquals($this->cleanXml($this->validXml1), $this->cleanXml(strval($transferConfig)));
+        $this->assertEquals(false,$transferConfig->getEnabled());
+    }
+
+    public function testInvalidXml1()
+    {
+        $transferConfig = new TransferAccelerationConfig();
+        $transferConfig->parseFromXml($this->invalidXml1);
+        $this->assertEquals(false,$transferConfig->getEnabled());
+    }
+
+    private function cleanXml($xml)
+    {
+        return str_replace("\n", "", str_replace("\r", "", $xml));
+    }
+}

+ 2 - 0
vendor/composer/autoload_files.php

@@ -6,6 +6,8 @@ $vendorDir = dirname(__DIR__);
 $baseDir = dirname($vendorDir);
 
 return array(
+    '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => $vendorDir . '/symfony/polyfill-mbstring/bootstrap.php',
+    '2cffec82183ee1cea088009cef9a6fc3' => $vendorDir . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
     '841780ea2e1d6545ea3a253239d59c05' => $vendorDir . '/qiniu/php-sdk/src/Qiniu/functions.php',
     '8dafcc6956460bc297e00381fed53e11' => $vendorDir . '/zoujingli/think-library/src/common.php',
 );

+ 1 - 0
vendor/composer/autoload_namespaces.php

@@ -7,4 +7,5 @@ $baseDir = dirname($vendorDir);
 
 return array(
     'PHPExcel' => array($vendorDir . '/phpoffice/phpexcel/Classes'),
+    'HTMLPurifier' => array($vendorDir . '/ezyang/htmlpurifier/library'),
 );

+ 8 - 0
vendor/composer/autoload_psr4.php

@@ -8,16 +8,24 @@ $baseDir = dirname($vendorDir);
 return array(
     'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'),
     'library\\' => array($vendorDir . '/zoujingli/think-library/src'),
+    'ZipStream\\' => array($vendorDir . '/maennchen/zipstream-php/src'),
     'WePay\\' => array($vendorDir . '/zoujingli/wechat-developer/WePay'),
     'WePayV3\\' => array($vendorDir . '/zoujingli/wechat-developer/WePayV3'),
     'WeOpen\\' => array($vendorDir . '/zoujingli/weopen-developer/WeOpen'),
     'WeMini\\' => array($vendorDir . '/zoujingli/wechat-developer/WeMini', $vendorDir . '/zoujingli/weopen-developer/WeMini'),
     'WeChat\\' => array($vendorDir . '/zoujingli/wechat-developer/WeChat', $vendorDir . '/zoujingli/weopen-developer/WeChat'),
+    'Symfony\\Polyfill\\Mbstring\\' => array($vendorDir . '/symfony/polyfill-mbstring'),
     'Symfony\\Component\\OptionsResolver\\' => array($vendorDir . '/symfony/options-resolver'),
     'Qiniu\\' => array($vendorDir . '/qiniu/php-sdk/src/Qiniu'),
+    'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
+    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),
+    'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
+    'PhpOffice\\PhpSpreadsheet\\' => array($vendorDir . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet'),
     'OSS\\' => array($vendorDir . '/aliyuncs/oss-sdk-php/src/OSS'),
     'MyCLabs\\Enum\\' => array($vendorDir . '/myclabs/php-enum/src'),
+    'Matrix\\' => array($vendorDir . '/markbaker/matrix/classes/src'),
     'Firebase\\JWT\\' => array($vendorDir . '/firebase/php-jwt/src'),
     'Endroid\\QrCode\\' => array($vendorDir . '/endroid/qr-code/src'),
+    'Complex\\' => array($vendorDir . '/markbaker/complex/classes/src'),
     'AliPay\\' => array($vendorDir . '/zoujingli/wechat-developer/AliPay'),
 );

+ 59 - 0
vendor/composer/autoload_static.php

@@ -7,6 +7,8 @@ namespace Composer\Autoload;
 class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
 {
     public static $files = array (
+        '0e6d7bf4a5811bfa5cf40c5ccd6fae6a' => __DIR__ . '/..' . '/symfony/polyfill-mbstring/bootstrap.php',
+        '2cffec82183ee1cea088009cef9a6fc3' => __DIR__ . '/..' . '/ezyang/htmlpurifier/library/HTMLPurifier.composer.php',
         '841780ea2e1d6545ea3a253239d59c05' => __DIR__ . '/..' . '/qiniu/php-sdk/src/Qiniu/functions.php',
         '8dafcc6956460bc297e00381fed53e11' => __DIR__ . '/..' . '/zoujingli/think-library/src/common.php',
     );
@@ -20,6 +22,10 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
         array (
             'library\\' => 8,
         ),
+        'Z' => 
+        array (
+            'ZipStream\\' => 10,
+        ),
         'W' => 
         array (
             'WePay\\' => 6,
@@ -30,12 +36,20 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
         ),
         'S' => 
         array (
+            'Symfony\\Polyfill\\Mbstring\\' => 26,
             'Symfony\\Component\\OptionsResolver\\' => 34,
         ),
         'Q' => 
         array (
             'Qiniu\\' => 6,
         ),
+        'P' => 
+        array (
+            'Psr\\SimpleCache\\' => 16,
+            'Psr\\Http\\Message\\' => 17,
+            'Psr\\Http\\Client\\' => 16,
+            'PhpOffice\\PhpSpreadsheet\\' => 25,
+        ),
         'O' => 
         array (
             'OSS\\' => 4,
@@ -43,6 +57,7 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
         'M' => 
         array (
             'MyCLabs\\Enum\\' => 13,
+            'Matrix\\' => 7,
         ),
         'F' => 
         array (
@@ -52,6 +67,10 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
         array (
             'Endroid\\QrCode\\' => 15,
         ),
+        'C' => 
+        array (
+            'Complex\\' => 8,
+        ),
         'A' => 
         array (
             'AliPay\\' => 7,
@@ -67,6 +86,10 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
         array (
             0 => __DIR__ . '/..' . '/zoujingli/think-library/src',
         ),
+        'ZipStream\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/maennchen/zipstream-php/src',
+        ),
         'WePay\\' => 
         array (
             0 => __DIR__ . '/..' . '/zoujingli/wechat-developer/WePay',
@@ -89,6 +112,10 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
             0 => __DIR__ . '/..' . '/zoujingli/wechat-developer/WeChat',
             1 => __DIR__ . '/..' . '/zoujingli/weopen-developer/WeChat',
         ),
+        'Symfony\\Polyfill\\Mbstring\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/symfony/polyfill-mbstring',
+        ),
         'Symfony\\Component\\OptionsResolver\\' => 
         array (
             0 => __DIR__ . '/..' . '/symfony/options-resolver',
@@ -97,6 +124,23 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
         array (
             0 => __DIR__ . '/..' . '/qiniu/php-sdk/src/Qiniu',
         ),
+        'Psr\\SimpleCache\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/simple-cache/src',
+        ),
+        'Psr\\Http\\Message\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/http-message/src',
+            1 => __DIR__ . '/..' . '/psr/http-factory/src',
+        ),
+        'Psr\\Http\\Client\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/psr/http-client/src',
+        ),
+        'PhpOffice\\PhpSpreadsheet\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/phpoffice/phpspreadsheet/src/PhpSpreadsheet',
+        ),
         'OSS\\' => 
         array (
             0 => __DIR__ . '/..' . '/aliyuncs/oss-sdk-php/src/OSS',
@@ -105,6 +149,10 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
         array (
             0 => __DIR__ . '/..' . '/myclabs/php-enum/src',
         ),
+        'Matrix\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/markbaker/matrix/classes/src',
+        ),
         'Firebase\\JWT\\' => 
         array (
             0 => __DIR__ . '/..' . '/firebase/php-jwt/src',
@@ -113,6 +161,10 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
         array (
             0 => __DIR__ . '/..' . '/endroid/qr-code/src',
         ),
+        'Complex\\' => 
+        array (
+            0 => __DIR__ . '/..' . '/markbaker/complex/classes/src',
+        ),
         'AliPay\\' => 
         array (
             0 => __DIR__ . '/..' . '/zoujingli/wechat-developer/AliPay',
@@ -127,6 +179,13 @@ class ComposerStaticInit4d241e9f8bb10d006cd7432f945fdb5b
                 0 => __DIR__ . '/..' . '/phpoffice/phpexcel/Classes',
             ),
         ),
+        'H' => 
+        array (
+            'HTMLPurifier' => 
+            array (
+                0 => __DIR__ . '/..' . '/ezyang/htmlpurifier/library',
+            ),
+        ),
     );
 
     public static $classMap = array (

+ 717 - 0
vendor/composer/installed.json

@@ -124,6 +124,66 @@
             "install-path": "../endroid/qr-code"
         },
         {
+            "name": "ezyang/htmlpurifier",
+            "version": "v4.14.0",
+            "version_normalized": "4.14.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/ezyang/htmlpurifier.git",
+                "reference": "12ab42bd6e742c70c0a52f7b82477fcd44e64b75"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/12ab42bd6e742c70c0a52f7b82477fcd44e64b75",
+                "reference": "12ab42bd6e742c70c0a52f7b82477fcd44e64b75",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": ">=5.2"
+            },
+            "time": "2021-12-25T01:21:49+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "library/HTMLPurifier.composer.php"
+                ],
+                "psr-0": {
+                    "HTMLPurifier": "library/"
+                },
+                "exclude-from-classmap": [
+                    "/library/HTMLPurifier/Language/"
+                ]
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "LGPL-2.1-or-later"
+            ],
+            "authors": [
+                {
+                    "name": "Edward Z. Yang",
+                    "email": "admin@htmlpurifier.org",
+                    "homepage": "http://ezyang.com"
+                }
+            ],
+            "description": "Standards compliant HTML filter written in PHP",
+            "homepage": "http://htmlpurifier.org/",
+            "keywords": [
+                "html"
+            ],
+            "support": {
+                "issues": "https://github.com/ezyang/htmlpurifier/issues",
+                "source": "https://github.com/ezyang/htmlpurifier/tree/v4.14.0"
+            },
+            "install-path": "../ezyang/htmlpurifier"
+        },
+        {
             "name": "firebase/php-jwt",
             "version": "v5.5.1",
             "version_normalized": "5.5.1.0",
@@ -190,6 +250,211 @@
             "install-path": "../firebase/php-jwt"
         },
         {
+            "name": "maennchen/zipstream-php",
+            "version": "2.1.0",
+            "version_normalized": "2.1.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/maennchen/ZipStream-PHP.git",
+                "reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/c4c5803cc1f93df3d2448478ef79394a5981cc58",
+                "reference": "c4c5803cc1f93df3d2448478ef79394a5981cc58",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "myclabs/php-enum": "^1.5",
+                "php": ">= 7.1",
+                "psr/http-message": "^1.0",
+                "symfony/polyfill-mbstring": "^1.0"
+            },
+            "require-dev": {
+                "ext-zip": "*",
+                "guzzlehttp/guzzle": ">= 6.3",
+                "mikey179/vfsstream": "^1.6",
+                "phpunit/phpunit": ">= 7.5"
+            },
+            "time": "2020-05-30T13:11:16+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "ZipStream\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Paul Duncan",
+                    "email": "pabs@pablotron.org"
+                },
+                {
+                    "name": "Jonatan Männchen",
+                    "email": "jonatan@maennchen.ch"
+                },
+                {
+                    "name": "Jesse Donat",
+                    "email": "donatj@gmail.com"
+                },
+                {
+                    "name": "András Kolesár",
+                    "email": "kolesar@kolesar.hu"
+                }
+            ],
+            "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.",
+            "keywords": [
+                "stream",
+                "zip"
+            ],
+            "support": {
+                "issues": "https://github.com/maennchen/ZipStream-PHP/issues",
+                "source": "https://github.com/maennchen/ZipStream-PHP/tree/master"
+            },
+            "funding": [
+                {
+                    "url": "https://opencollective.com/zipstream",
+                    "type": "open_collective"
+                }
+            ],
+            "install-path": "../maennchen/zipstream-php"
+        },
+        {
+            "name": "markbaker/complex",
+            "version": "3.0.1",
+            "version_normalized": "3.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/MarkBaker/PHPComplex.git",
+                "reference": "ab8bc271e404909db09ff2d5ffa1e538085c0f22"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/ab8bc271e404909db09ff2d5ffa1e538085c0f22",
+                "reference": "ab8bc271e404909db09ff2d5ffa1e538085c0f22",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": "^7.2 || ^8.0"
+            },
+            "require-dev": {
+                "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
+                "phpcompatibility/php-compatibility": "^9.0",
+                "phpunit/phpunit": "^7.0 || ^8.0 || ^9.3",
+                "squizlabs/php_codesniffer": "^3.4"
+            },
+            "time": "2021-06-29T15:32:53+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Complex\\": "classes/src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mark Baker",
+                    "email": "mark@lange.demon.co.uk"
+                }
+            ],
+            "description": "PHP Class for working with complex numbers",
+            "homepage": "https://github.com/MarkBaker/PHPComplex",
+            "keywords": [
+                "complex",
+                "mathematics"
+            ],
+            "support": {
+                "issues": "https://github.com/MarkBaker/PHPComplex/issues",
+                "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.1"
+            },
+            "install-path": "../markbaker/complex"
+        },
+        {
+            "name": "markbaker/matrix",
+            "version": "3.0.0",
+            "version_normalized": "3.0.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/MarkBaker/PHPMatrix.git",
+                "reference": "c66aefcafb4f6c269510e9ac46b82619a904c576"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/c66aefcafb4f6c269510e9ac46b82619a904c576",
+                "reference": "c66aefcafb4f6c269510e9ac46b82619a904c576",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": "^7.1 || ^8.0"
+            },
+            "require-dev": {
+                "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0",
+                "phpcompatibility/php-compatibility": "^9.0",
+                "phpdocumentor/phpdocumentor": "2.*",
+                "phploc/phploc": "^4.0",
+                "phpmd/phpmd": "2.*",
+                "phpunit/phpunit": "^7.0 || ^8.0 || ^9.3",
+                "sebastian/phpcpd": "^4.0",
+                "squizlabs/php_codesniffer": "^3.4"
+            },
+            "time": "2021-07-01T19:01:15+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Matrix\\": "classes/src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Mark Baker",
+                    "email": "mark@demon-angel.eu"
+                }
+            ],
+            "description": "PHP Class for working with matrices",
+            "homepage": "https://github.com/MarkBaker/PHPMatrix",
+            "keywords": [
+                "mathematics",
+                "matrix",
+                "vector"
+            ],
+            "support": {
+                "issues": "https://github.com/MarkBaker/PHPMatrix/issues",
+                "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.0"
+            },
+            "install-path": "../markbaker/matrix"
+        },
+        {
             "name": "myclabs/php-enum",
             "version": "1.6.6",
             "version_normalized": "1.6.6.0",
@@ -319,6 +584,366 @@
             "install-path": "../phpoffice/phpexcel"
         },
         {
+            "name": "phpoffice/phpspreadsheet",
+            "version": "1.24.0",
+            "version_normalized": "1.24.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/PHPOffice/PhpSpreadsheet.git",
+                "reference": "ebe8745c92a7cac4514d040758393b5399633b83"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/ebe8745c92a7cac4514d040758393b5399633b83",
+                "reference": "ebe8745c92a7cac4514d040758393b5399633b83",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "ext-ctype": "*",
+                "ext-dom": "*",
+                "ext-fileinfo": "*",
+                "ext-gd": "*",
+                "ext-iconv": "*",
+                "ext-libxml": "*",
+                "ext-mbstring": "*",
+                "ext-simplexml": "*",
+                "ext-xml": "*",
+                "ext-xmlreader": "*",
+                "ext-xmlwriter": "*",
+                "ext-zip": "*",
+                "ext-zlib": "*",
+                "ezyang/htmlpurifier": "^4.13",
+                "maennchen/zipstream-php": "^2.1",
+                "markbaker/complex": "^3.0",
+                "markbaker/matrix": "^3.0",
+                "php": "^7.3 || ^8.0",
+                "psr/http-client": "^1.0",
+                "psr/http-factory": "^1.0",
+                "psr/simple-cache": "^1.0 || ^2.0"
+            },
+            "require-dev": {
+                "dealerdirect/phpcodesniffer-composer-installer": "dev-master",
+                "dompdf/dompdf": "^1.0 || ^2.0",
+                "friendsofphp/php-cs-fixer": "^3.2",
+                "jpgraph/jpgraph": "^4.0",
+                "mpdf/mpdf": "8.1.1",
+                "phpcompatibility/php-compatibility": "^9.3",
+                "phpstan/phpstan": "^1.1",
+                "phpstan/phpstan-phpunit": "^1.0",
+                "phpunit/phpunit": "^8.5 || ^9.0",
+                "squizlabs/php_codesniffer": "^3.7",
+                "tecnickcom/tcpdf": "^6.4"
+            },
+            "suggest": {
+                "dompdf/dompdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)",
+                "jpgraph/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers",
+                "mpdf/mpdf": "Option for rendering PDF with PDF Writer",
+                "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer (doesn't yet support PHP8)"
+            },
+            "time": "2022-07-09T13:49:09+00:00",
+            "type": "library",
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Maarten Balliauw",
+                    "homepage": "https://blog.maartenballiauw.be"
+                },
+                {
+                    "name": "Mark Baker",
+                    "homepage": "https://markbakeruk.net"
+                },
+                {
+                    "name": "Franck Lefevre",
+                    "homepage": "https://rootslabs.net"
+                },
+                {
+                    "name": "Erik Tilt"
+                },
+                {
+                    "name": "Adrien Crivelli"
+                }
+            ],
+            "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine",
+            "homepage": "https://github.com/PHPOffice/PhpSpreadsheet",
+            "keywords": [
+                "OpenXML",
+                "excel",
+                "gnumeric",
+                "ods",
+                "php",
+                "spreadsheet",
+                "xls",
+                "xlsx"
+            ],
+            "support": {
+                "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues",
+                "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.24.0"
+            },
+            "install-path": "../phpoffice/phpspreadsheet"
+        },
+        {
+            "name": "psr/http-client",
+            "version": "1.0.1",
+            "version_normalized": "1.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-client.git",
+                "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
+                "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": "^7.0 || ^8.0",
+                "psr/http-message": "^1.0"
+            },
+            "time": "2020-06-29T06:28:15+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Client\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP clients",
+            "homepage": "https://github.com/php-fig/http-client",
+            "keywords": [
+                "http",
+                "http-client",
+                "psr",
+                "psr-18"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/http-client/tree/master"
+            },
+            "install-path": "../psr/http-client"
+        },
+        {
+            "name": "psr/http-factory",
+            "version": "1.0.1",
+            "version_normalized": "1.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-factory.git",
+                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": ">=7.0.0",
+                "psr/http-message": "^1.0"
+            },
+            "time": "2019-04-30T12:38:16+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Message\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interfaces for PSR-7 HTTP message factories",
+            "keywords": [
+                "factory",
+                "http",
+                "message",
+                "psr",
+                "psr-17",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/http-factory/tree/master"
+            },
+            "install-path": "../psr/http-factory"
+        },
+        {
+            "name": "psr/http-message",
+            "version": "1.0.1",
+            "version_normalized": "1.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/http-message.git",
+                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
+                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "time": "2016-08-06T14:39:51+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\Http\\Message\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interface for HTTP messages",
+            "homepage": "https://github.com/php-fig/http-message",
+            "keywords": [
+                "http",
+                "http-message",
+                "psr",
+                "psr-7",
+                "request",
+                "response"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/http-message/tree/master"
+            },
+            "install-path": "../psr/http-message"
+        },
+        {
+            "name": "psr/simple-cache",
+            "version": "1.0.1",
+            "version_normalized": "1.0.1.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/php-fig/simple-cache.git",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "reference": "408d5eafb83c57f6365a3ca330ff23aa4a5fa39b",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": ">=5.3.0"
+            },
+            "time": "2017-10-23T01:57:42+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-master": "1.0.x-dev"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "psr-4": {
+                    "Psr\\SimpleCache\\": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "PHP-FIG",
+                    "homepage": "http://www.php-fig.org/"
+                }
+            ],
+            "description": "Common interfaces for simple caching",
+            "keywords": [
+                "cache",
+                "caching",
+                "psr",
+                "psr-16",
+                "simple-cache"
+            ],
+            "support": {
+                "source": "https://github.com/php-fig/simple-cache/tree/master"
+            },
+            "install-path": "../psr/simple-cache"
+        },
+        {
             "name": "qiniu/php-sdk",
             "version": "v7.6.0",
             "version_normalized": "7.6.0.0",
@@ -460,6 +1085,98 @@
             "install-path": "../symfony/options-resolver"
         },
         {
+            "name": "symfony/polyfill-mbstring",
+            "version": "v1.26.0",
+            "version_normalized": "1.26.0.0",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/symfony/polyfill-mbstring.git",
+                "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
+                "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e",
+                "shasum": "",
+                "mirrors": [
+                    {
+                        "url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
+                        "preferred": true
+                    }
+                ]
+            },
+            "require": {
+                "php": ">=7.1"
+            },
+            "provide": {
+                "ext-mbstring": "*"
+            },
+            "suggest": {
+                "ext-mbstring": "For best performance"
+            },
+            "time": "2022-05-24T11:49:31+00:00",
+            "type": "library",
+            "extra": {
+                "branch-alias": {
+                    "dev-main": "1.26-dev"
+                },
+                "thanks": {
+                    "name": "symfony/polyfill",
+                    "url": "https://github.com/symfony/polyfill"
+                }
+            },
+            "installation-source": "dist",
+            "autoload": {
+                "files": [
+                    "bootstrap.php"
+                ],
+                "psr-4": {
+                    "Symfony\\Polyfill\\Mbstring\\": ""
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Nicolas Grekas",
+                    "email": "p@tchwork.com"
+                },
+                {
+                    "name": "Symfony Community",
+                    "homepage": "https://symfony.com/contributors"
+                }
+            ],
+            "description": "Symfony polyfill for the Mbstring extension",
+            "homepage": "https://symfony.com",
+            "keywords": [
+                "compatibility",
+                "mbstring",
+                "polyfill",
+                "portable",
+                "shim"
+            ],
+            "support": {
+                "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0"
+            },
+            "funding": [
+                {
+                    "url": "https://symfony.com/sponsor",
+                    "type": "custom"
+                },
+                {
+                    "url": "https://github.com/fabpot",
+                    "type": "github"
+                },
+                {
+                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+                    "type": "tidelift"
+                }
+            ],
+            "install-path": "../symfony/polyfill-mbstring"
+        },
+        {
             "name": "topthink/framework",
             "version": "v5.1.41",
             "version_normalized": "5.1.41.0",

+ 92 - 2
vendor/composer/installed.php

@@ -3,7 +3,7 @@
         'name' => 'zoujingli/thinkadmin',
         'pretty_version' => 'dev-master',
         'version' => 'dev-master',
-        'reference' => '1dddc575d7217d532dee3c877fc51667b9e710a7',
+        'reference' => 'ac8fd5b9eb3ff54b21083d42e242516315958e60',
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
@@ -28,6 +28,15 @@
             'aliases' => array(),
             'dev_requirement' => false,
         ),
+        'ezyang/htmlpurifier' => array(
+            'pretty_version' => 'v4.14.0',
+            'version' => '4.14.0.0',
+            'reference' => '12ab42bd6e742c70c0a52f7b82477fcd44e64b75',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../ezyang/htmlpurifier',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
         'firebase/php-jwt' => array(
             'pretty_version' => 'v5.5.1',
             'version' => '5.5.1.0',
@@ -37,6 +46,33 @@
             'aliases' => array(),
             'dev_requirement' => false,
         ),
+        'maennchen/zipstream-php' => array(
+            'pretty_version' => '2.1.0',
+            'version' => '2.1.0.0',
+            'reference' => 'c4c5803cc1f93df3d2448478ef79394a5981cc58',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../maennchen/zipstream-php',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'markbaker/complex' => array(
+            'pretty_version' => '3.0.1',
+            'version' => '3.0.1.0',
+            'reference' => 'ab8bc271e404909db09ff2d5ffa1e538085c0f22',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../markbaker/complex',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'markbaker/matrix' => array(
+            'pretty_version' => '3.0.0',
+            'version' => '3.0.0.0',
+            'reference' => 'c66aefcafb4f6c269510e9ac46b82619a904c576',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../markbaker/matrix',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
         'myclabs/php-enum' => array(
             'pretty_version' => '1.6.6',
             'version' => '1.6.6.0',
@@ -55,6 +91,51 @@
             'aliases' => array(),
             'dev_requirement' => false,
         ),
+        'phpoffice/phpspreadsheet' => array(
+            'pretty_version' => '1.24.0',
+            'version' => '1.24.0.0',
+            'reference' => 'ebe8745c92a7cac4514d040758393b5399633b83',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../phpoffice/phpspreadsheet',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/http-client' => array(
+            'pretty_version' => '1.0.1',
+            'version' => '1.0.1.0',
+            'reference' => '2dfb5f6c5eff0e91e20e913f8c5452ed95b86621',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/http-client',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/http-factory' => array(
+            'pretty_version' => '1.0.1',
+            'version' => '1.0.1.0',
+            'reference' => '12ac7fcd07e5b077433f5f2bee95b3a771bf61be',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/http-factory',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/http-message' => array(
+            'pretty_version' => '1.0.1',
+            'version' => '1.0.1.0',
+            'reference' => 'f6561bf28d520154e4b0ec72be95418abe6d9363',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/http-message',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
+        'psr/simple-cache' => array(
+            'pretty_version' => '1.0.1',
+            'version' => '1.0.1.0',
+            'reference' => '408d5eafb83c57f6365a3ca330ff23aa4a5fa39b',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../psr/simple-cache',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
         'qiniu/php-sdk' => array(
             'pretty_version' => 'v7.6.0',
             'version' => '7.6.0.0',
@@ -73,6 +154,15 @@
             'aliases' => array(),
             'dev_requirement' => false,
         ),
+        'symfony/polyfill-mbstring' => array(
+            'pretty_version' => 'v1.26.0',
+            'version' => '1.26.0.0',
+            'reference' => '9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e',
+            'type' => 'library',
+            'install_path' => __DIR__ . '/../symfony/polyfill-mbstring',
+            'aliases' => array(),
+            'dev_requirement' => false,
+        ),
         'topthink/framework' => array(
             'pretty_version' => 'v5.1.41',
             'version' => '5.1.41.0',
@@ -112,7 +202,7 @@
         'zoujingli/thinkadmin' => array(
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => '1dddc575d7217d532dee3c877fc51667b9e710a7',
+            'reference' => 'ac8fd5b9eb3ff54b21083d42e242516315958e60',
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),

+ 2 - 2
vendor/composer/platform_check.php

@@ -4,8 +4,8 @@
 
 $issues = array();
 
-if (!(PHP_VERSION_ID >= 50600)) {
-    $issues[] = 'Your Composer dependencies require a PHP version ">= 5.6.0". You are running ' . PHP_VERSION . '.';
+if (!(PHP_VERSION_ID >= 70300)) {
+    $issues[] = 'Your Composer dependencies require a PHP version ">= 7.3.0". You are running ' . PHP_VERSION . '.';
 }
 
 if ($issues) {

+ 9 - 0
vendor/ezyang/htmlpurifier/CREDITS

@@ -0,0 +1,9 @@
+
+CREDITS
+
+Almost everything written by Edward Z. Yang (Ambush Commander).  Lots of thanks
+to the DevNetwork Community for their help (see docs/ref-devnetwork.html for
+more details), Feyd especially (namely IPv6 and optimization).  Thanks to RSnake
+for letting me package his fantastic XSS cheatsheet for a smoketest.
+
+    vim: et sw=4 sts=4

+ 504 - 0
vendor/ezyang/htmlpurifier/LICENSE

@@ -0,0 +1,504 @@
+		  GNU LESSER GENERAL PUBLIC LICENSE
+		       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+		  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+			    NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
+    vim: et sw=4 sts=4

+ 29 - 0
vendor/ezyang/htmlpurifier/README.md

@@ -0,0 +1,29 @@
+HTML Purifier [![Build Status](https://github.com/ezyang/htmlpurifier/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/ezyang/htmlpurifier/actions/workflows/ci.yml)
+=============
+
+HTML Purifier is an HTML filtering solution that uses a unique combination
+of robust whitelists and aggressive parsing to ensure that not only are
+XSS attacks thwarted, but the resulting HTML is standards compliant.
+
+HTML Purifier is oriented towards richly formatted documents from
+untrusted sources that require CSS and a full tag-set.  This library can
+be configured to accept a more restrictive set of tags, but it won't be
+as efficient as more bare-bones parsers. It will, however, do the job
+right, which may be more important.
+
+Places to go:
+
+* See INSTALL for a quick installation guide
+* See docs/ for developer-oriented documentation, code examples and
+  an in-depth installation guide.
+* See WYSIWYG for information on editors like TinyMCE and FCKeditor
+
+HTML Purifier can be found on the web at: [http://htmlpurifier.org/](http://htmlpurifier.org/)
+
+## Installation
+
+Package available on [Composer](https://packagist.org/packages/ezyang/htmlpurifier).
+
+If you're using Composer to manage dependencies, you can use
+
+    $ composer require ezyang/htmlpurifier

+ 1 - 0
vendor/ezyang/htmlpurifier/VERSION

@@ -0,0 +1 @@
+4.14.0

+ 25 - 0
vendor/ezyang/htmlpurifier/composer.json

@@ -0,0 +1,25 @@
+{
+    "name": "ezyang/htmlpurifier",
+    "description": "Standards compliant HTML filter written in PHP",
+    "type": "library",
+    "keywords": ["html"],
+    "homepage": "http://htmlpurifier.org/",
+    "license": "LGPL-2.1-or-later",
+    "authors": [
+        {
+            "name": "Edward Z. Yang",
+            "email": "admin@htmlpurifier.org",
+            "homepage": "http://ezyang.com"
+        }
+    ],
+    "require": {
+        "php": ">=5.2"
+    },
+    "autoload": {
+        "psr-0": { "HTMLPurifier": "library/" },
+        "files": ["library/HTMLPurifier.composer.php"],
+        "exclude-from-classmap": [
+            "/library/HTMLPurifier/Language/"
+        ]
+    }
+}

+ 11 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.auto.php

@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * This is a stub include that automatically configures the include path.
+ */
+
+set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() );
+require_once 'HTMLPurifier/Bootstrap.php';
+require_once 'HTMLPurifier.autoload.php';
+
+// vim: et sw=4 sts=4

+ 14 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.autoload-legacy.php

@@ -0,0 +1,14 @@
+<?php
+
+/**
+ * @file
+ * Legacy autoloader for systems lacking spl_autoload_register
+ *
+ */
+
+spl_autoload_register(function($class)
+{
+     return HTMLPurifier_Bootstrap::autoload($class);
+});
+
+// vim: et sw=4 sts=4

+ 25 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.autoload.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Convenience file that registers autoload handler for HTML Purifier.
+ * It also does some sanity checks.
+ */
+
+if (function_exists('spl_autoload_register') && function_exists('spl_autoload_unregister')) {
+    // We need unregister for our pre-registering functionality
+    HTMLPurifier_Bootstrap::registerAutoload();
+    if (function_exists('__autoload')) {
+        // Be polite and ensure that userland autoload gets retained
+        spl_autoload_register('__autoload');
+    }
+} elseif (!function_exists('__autoload')) {
+    require dirname(__FILE__) . '/HTMLPurifier.autoload-legacy.php';
+}
+
+// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.zend_ze1_compatibility_modeRemoved
+if (ini_get('zend.ze1_compatibility_mode')) {
+    trigger_error("HTML Purifier is not compatible with zend.ze1_compatibility_mode; please turn it off", E_USER_ERROR);
+}
+
+// vim: et sw=4 sts=4

+ 4 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.composer.php

@@ -0,0 +1,4 @@
+<?php
+if (!defined('HTMLPURIFIER_PREFIX')) {
+    define('HTMLPURIFIER_PREFIX', dirname(__FILE__));
+}

+ 25 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.func.php

@@ -0,0 +1,25 @@
+<?php
+
+/**
+ * @file
+ * Defines a function wrapper for HTML Purifier for quick use.
+ * @note ''HTMLPurifier()'' is NOT the same as ''new HTMLPurifier()''
+ */
+
+/**
+ * Purify HTML.
+ * @param string $html String HTML to purify
+ * @param mixed $config Configuration to use, can be any value accepted by
+ *        HTMLPurifier_Config::create()
+ * @return string
+ */
+function HTMLPurifier($html, $config = null)
+{
+    static $purifier = false;
+    if (!$purifier) {
+        $purifier = new HTMLPurifier();
+    }
+    return $purifier->purify($html, $config);
+}
+
+// vim: et sw=4 sts=4

+ 234 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.includes.php

@@ -0,0 +1,234 @@
+<?php
+
+/**
+ * @file
+ * This file was auto-generated by generate-includes.php and includes all of
+ * the core files required by HTML Purifier. Use this if performance is a
+ * primary concern and you are using an opcode cache. PLEASE DO NOT EDIT THIS
+ * FILE, changes will be overwritten the next time the script is run.
+ *
+ * @version 4.14.0
+ *
+ * @warning
+ *      You must *not* include any other HTML Purifier files before this file,
+ *      because 'require' not 'require_once' is used.
+ *
+ * @warning
+ *      This file requires that the include path contains the HTML Purifier
+ *      library directory; this is not auto-set.
+ */
+
+require 'HTMLPurifier.php';
+require 'HTMLPurifier/Arborize.php';
+require 'HTMLPurifier/AttrCollections.php';
+require 'HTMLPurifier/AttrDef.php';
+require 'HTMLPurifier/AttrTransform.php';
+require 'HTMLPurifier/AttrTypes.php';
+require 'HTMLPurifier/AttrValidator.php';
+require 'HTMLPurifier/Bootstrap.php';
+require 'HTMLPurifier/Definition.php';
+require 'HTMLPurifier/CSSDefinition.php';
+require 'HTMLPurifier/ChildDef.php';
+require 'HTMLPurifier/Config.php';
+require 'HTMLPurifier/ConfigSchema.php';
+require 'HTMLPurifier/ContentSets.php';
+require 'HTMLPurifier/Context.php';
+require 'HTMLPurifier/DefinitionCache.php';
+require 'HTMLPurifier/DefinitionCacheFactory.php';
+require 'HTMLPurifier/Doctype.php';
+require 'HTMLPurifier/DoctypeRegistry.php';
+require 'HTMLPurifier/ElementDef.php';
+require 'HTMLPurifier/Encoder.php';
+require 'HTMLPurifier/EntityLookup.php';
+require 'HTMLPurifier/EntityParser.php';
+require 'HTMLPurifier/ErrorCollector.php';
+require 'HTMLPurifier/ErrorStruct.php';
+require 'HTMLPurifier/Exception.php';
+require 'HTMLPurifier/Filter.php';
+require 'HTMLPurifier/Generator.php';
+require 'HTMLPurifier/HTMLDefinition.php';
+require 'HTMLPurifier/HTMLModule.php';
+require 'HTMLPurifier/HTMLModuleManager.php';
+require 'HTMLPurifier/IDAccumulator.php';
+require 'HTMLPurifier/Injector.php';
+require 'HTMLPurifier/Language.php';
+require 'HTMLPurifier/LanguageFactory.php';
+require 'HTMLPurifier/Length.php';
+require 'HTMLPurifier/Lexer.php';
+require 'HTMLPurifier/Node.php';
+require 'HTMLPurifier/PercentEncoder.php';
+require 'HTMLPurifier/PropertyList.php';
+require 'HTMLPurifier/PropertyListIterator.php';
+require 'HTMLPurifier/Queue.php';
+require 'HTMLPurifier/Strategy.php';
+require 'HTMLPurifier/StringHash.php';
+require 'HTMLPurifier/StringHashParser.php';
+require 'HTMLPurifier/TagTransform.php';
+require 'HTMLPurifier/Token.php';
+require 'HTMLPurifier/TokenFactory.php';
+require 'HTMLPurifier/URI.php';
+require 'HTMLPurifier/URIDefinition.php';
+require 'HTMLPurifier/URIFilter.php';
+require 'HTMLPurifier/URIParser.php';
+require 'HTMLPurifier/URIScheme.php';
+require 'HTMLPurifier/URISchemeRegistry.php';
+require 'HTMLPurifier/UnitConverter.php';
+require 'HTMLPurifier/VarParser.php';
+require 'HTMLPurifier/VarParserException.php';
+require 'HTMLPurifier/Zipper.php';
+require 'HTMLPurifier/AttrDef/CSS.php';
+require 'HTMLPurifier/AttrDef/Clone.php';
+require 'HTMLPurifier/AttrDef/Enum.php';
+require 'HTMLPurifier/AttrDef/Integer.php';
+require 'HTMLPurifier/AttrDef/Lang.php';
+require 'HTMLPurifier/AttrDef/Switch.php';
+require 'HTMLPurifier/AttrDef/Text.php';
+require 'HTMLPurifier/AttrDef/URI.php';
+require 'HTMLPurifier/AttrDef/CSS/Number.php';
+require 'HTMLPurifier/AttrDef/CSS/AlphaValue.php';
+require 'HTMLPurifier/AttrDef/CSS/Background.php';
+require 'HTMLPurifier/AttrDef/CSS/BackgroundPosition.php';
+require 'HTMLPurifier/AttrDef/CSS/Border.php';
+require 'HTMLPurifier/AttrDef/CSS/Color.php';
+require 'HTMLPurifier/AttrDef/CSS/Composite.php';
+require 'HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php';
+require 'HTMLPurifier/AttrDef/CSS/Filter.php';
+require 'HTMLPurifier/AttrDef/CSS/Font.php';
+require 'HTMLPurifier/AttrDef/CSS/FontFamily.php';
+require 'HTMLPurifier/AttrDef/CSS/Ident.php';
+require 'HTMLPurifier/AttrDef/CSS/ImportantDecorator.php';
+require 'HTMLPurifier/AttrDef/CSS/Length.php';
+require 'HTMLPurifier/AttrDef/CSS/ListStyle.php';
+require 'HTMLPurifier/AttrDef/CSS/Multiple.php';
+require 'HTMLPurifier/AttrDef/CSS/Percentage.php';
+require 'HTMLPurifier/AttrDef/CSS/TextDecoration.php';
+require 'HTMLPurifier/AttrDef/CSS/URI.php';
+require 'HTMLPurifier/AttrDef/HTML/Bool.php';
+require 'HTMLPurifier/AttrDef/HTML/Nmtokens.php';
+require 'HTMLPurifier/AttrDef/HTML/Class.php';
+require 'HTMLPurifier/AttrDef/HTML/Color.php';
+require 'HTMLPurifier/AttrDef/HTML/FrameTarget.php';
+require 'HTMLPurifier/AttrDef/HTML/ID.php';
+require 'HTMLPurifier/AttrDef/HTML/Pixels.php';
+require 'HTMLPurifier/AttrDef/HTML/Length.php';
+require 'HTMLPurifier/AttrDef/HTML/LinkTypes.php';
+require 'HTMLPurifier/AttrDef/HTML/MultiLength.php';
+require 'HTMLPurifier/AttrDef/URI/Email.php';
+require 'HTMLPurifier/AttrDef/URI/Host.php';
+require 'HTMLPurifier/AttrDef/URI/IPv4.php';
+require 'HTMLPurifier/AttrDef/URI/IPv6.php';
+require 'HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php';
+require 'HTMLPurifier/AttrTransform/Background.php';
+require 'HTMLPurifier/AttrTransform/BdoDir.php';
+require 'HTMLPurifier/AttrTransform/BgColor.php';
+require 'HTMLPurifier/AttrTransform/BoolToCSS.php';
+require 'HTMLPurifier/AttrTransform/Border.php';
+require 'HTMLPurifier/AttrTransform/EnumToCSS.php';
+require 'HTMLPurifier/AttrTransform/ImgRequired.php';
+require 'HTMLPurifier/AttrTransform/ImgSpace.php';
+require 'HTMLPurifier/AttrTransform/Input.php';
+require 'HTMLPurifier/AttrTransform/Lang.php';
+require 'HTMLPurifier/AttrTransform/Length.php';
+require 'HTMLPurifier/AttrTransform/Name.php';
+require 'HTMLPurifier/AttrTransform/NameSync.php';
+require 'HTMLPurifier/AttrTransform/Nofollow.php';
+require 'HTMLPurifier/AttrTransform/SafeEmbed.php';
+require 'HTMLPurifier/AttrTransform/SafeObject.php';
+require 'HTMLPurifier/AttrTransform/SafeParam.php';
+require 'HTMLPurifier/AttrTransform/ScriptRequired.php';
+require 'HTMLPurifier/AttrTransform/TargetBlank.php';
+require 'HTMLPurifier/AttrTransform/TargetNoopener.php';
+require 'HTMLPurifier/AttrTransform/TargetNoreferrer.php';
+require 'HTMLPurifier/AttrTransform/Textarea.php';
+require 'HTMLPurifier/ChildDef/Chameleon.php';
+require 'HTMLPurifier/ChildDef/Custom.php';
+require 'HTMLPurifier/ChildDef/Empty.php';
+require 'HTMLPurifier/ChildDef/List.php';
+require 'HTMLPurifier/ChildDef/Required.php';
+require 'HTMLPurifier/ChildDef/Optional.php';
+require 'HTMLPurifier/ChildDef/StrictBlockquote.php';
+require 'HTMLPurifier/ChildDef/Table.php';
+require 'HTMLPurifier/DefinitionCache/Decorator.php';
+require 'HTMLPurifier/DefinitionCache/Null.php';
+require 'HTMLPurifier/DefinitionCache/Serializer.php';
+require 'HTMLPurifier/DefinitionCache/Decorator/Cleanup.php';
+require 'HTMLPurifier/DefinitionCache/Decorator/Memory.php';
+require 'HTMLPurifier/HTMLModule/Bdo.php';
+require 'HTMLPurifier/HTMLModule/CommonAttributes.php';
+require 'HTMLPurifier/HTMLModule/Edit.php';
+require 'HTMLPurifier/HTMLModule/Forms.php';
+require 'HTMLPurifier/HTMLModule/Hypertext.php';
+require 'HTMLPurifier/HTMLModule/Iframe.php';
+require 'HTMLPurifier/HTMLModule/Image.php';
+require 'HTMLPurifier/HTMLModule/Legacy.php';
+require 'HTMLPurifier/HTMLModule/List.php';
+require 'HTMLPurifier/HTMLModule/Name.php';
+require 'HTMLPurifier/HTMLModule/Nofollow.php';
+require 'HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
+require 'HTMLPurifier/HTMLModule/Object.php';
+require 'HTMLPurifier/HTMLModule/Presentation.php';
+require 'HTMLPurifier/HTMLModule/Proprietary.php';
+require 'HTMLPurifier/HTMLModule/Ruby.php';
+require 'HTMLPurifier/HTMLModule/SafeEmbed.php';
+require 'HTMLPurifier/HTMLModule/SafeObject.php';
+require 'HTMLPurifier/HTMLModule/SafeScripting.php';
+require 'HTMLPurifier/HTMLModule/Scripting.php';
+require 'HTMLPurifier/HTMLModule/StyleAttribute.php';
+require 'HTMLPurifier/HTMLModule/Tables.php';
+require 'HTMLPurifier/HTMLModule/Target.php';
+require 'HTMLPurifier/HTMLModule/TargetBlank.php';
+require 'HTMLPurifier/HTMLModule/TargetNoopener.php';
+require 'HTMLPurifier/HTMLModule/TargetNoreferrer.php';
+require 'HTMLPurifier/HTMLModule/Text.php';
+require 'HTMLPurifier/HTMLModule/Tidy.php';
+require 'HTMLPurifier/HTMLModule/XMLCommonAttributes.php';
+require 'HTMLPurifier/HTMLModule/Tidy/Name.php';
+require 'HTMLPurifier/HTMLModule/Tidy/Proprietary.php';
+require 'HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php';
+require 'HTMLPurifier/HTMLModule/Tidy/Strict.php';
+require 'HTMLPurifier/HTMLModule/Tidy/Transitional.php';
+require 'HTMLPurifier/HTMLModule/Tidy/XHTML.php';
+require 'HTMLPurifier/Injector/AutoParagraph.php';
+require 'HTMLPurifier/Injector/DisplayLinkURI.php';
+require 'HTMLPurifier/Injector/Linkify.php';
+require 'HTMLPurifier/Injector/PurifierLinkify.php';
+require 'HTMLPurifier/Injector/RemoveEmpty.php';
+require 'HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php';
+require 'HTMLPurifier/Injector/SafeObject.php';
+require 'HTMLPurifier/Lexer/DOMLex.php';
+require 'HTMLPurifier/Lexer/DirectLex.php';
+require 'HTMLPurifier/Node/Comment.php';
+require 'HTMLPurifier/Node/Element.php';
+require 'HTMLPurifier/Node/Text.php';
+require 'HTMLPurifier/Strategy/Composite.php';
+require 'HTMLPurifier/Strategy/Core.php';
+require 'HTMLPurifier/Strategy/FixNesting.php';
+require 'HTMLPurifier/Strategy/MakeWellFormed.php';
+require 'HTMLPurifier/Strategy/RemoveForeignElements.php';
+require 'HTMLPurifier/Strategy/ValidateAttributes.php';
+require 'HTMLPurifier/TagTransform/Font.php';
+require 'HTMLPurifier/TagTransform/Simple.php';
+require 'HTMLPurifier/Token/Comment.php';
+require 'HTMLPurifier/Token/Tag.php';
+require 'HTMLPurifier/Token/Empty.php';
+require 'HTMLPurifier/Token/End.php';
+require 'HTMLPurifier/Token/Start.php';
+require 'HTMLPurifier/Token/Text.php';
+require 'HTMLPurifier/URIFilter/DisableExternal.php';
+require 'HTMLPurifier/URIFilter/DisableExternalResources.php';
+require 'HTMLPurifier/URIFilter/DisableResources.php';
+require 'HTMLPurifier/URIFilter/HostBlacklist.php';
+require 'HTMLPurifier/URIFilter/MakeAbsolute.php';
+require 'HTMLPurifier/URIFilter/Munge.php';
+require 'HTMLPurifier/URIFilter/SafeIframe.php';
+require 'HTMLPurifier/URIScheme/data.php';
+require 'HTMLPurifier/URIScheme/file.php';
+require 'HTMLPurifier/URIScheme/ftp.php';
+require 'HTMLPurifier/URIScheme/http.php';
+require 'HTMLPurifier/URIScheme/https.php';
+require 'HTMLPurifier/URIScheme/mailto.php';
+require 'HTMLPurifier/URIScheme/news.php';
+require 'HTMLPurifier/URIScheme/nntp.php';
+require 'HTMLPurifier/URIScheme/tel.php';
+require 'HTMLPurifier/VarParser/Flexible.php';
+require 'HTMLPurifier/VarParser/Native.php';

+ 30 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.kses.php

@@ -0,0 +1,30 @@
+<?php
+
+/**
+ * @file
+ * Emulation layer for code that used kses(), substituting in HTML Purifier.
+ */
+
+require_once dirname(__FILE__) . '/HTMLPurifier.auto.php';
+
+function kses($string, $allowed_html, $allowed_protocols = null)
+{
+    $config = HTMLPurifier_Config::createDefault();
+    $allowed_elements = array();
+    $allowed_attributes = array();
+    foreach ($allowed_html as $element => $attributes) {
+        $allowed_elements[$element] = true;
+        foreach ($attributes as $attribute => $x) {
+            $allowed_attributes["$element.$attribute"] = true;
+        }
+    }
+    $config->set('HTML.AllowedElements', $allowed_elements);
+    $config->set('HTML.AllowedAttributes', $allowed_attributes);
+    if ($allowed_protocols !== null) {
+        $config->set('URI.AllowedSchemes', $allowed_protocols);
+    }
+    $purifier = new HTMLPurifier($config);
+    return $purifier->purify($string);
+}
+
+// vim: et sw=4 sts=4

+ 11 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.path.php

@@ -0,0 +1,11 @@
+<?php
+
+/**
+ * @file
+ * Convenience stub file that adds HTML Purifier's library file to the path
+ * without any other side-effects.
+ */
+
+set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path() );
+
+// vim: et sw=4 sts=4

+ 297 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.php

@@ -0,0 +1,297 @@
+<?php
+
+/*! @mainpage
+ *
+ * HTML Purifier is an HTML filter that will take an arbitrary snippet of
+ * HTML and rigorously test, validate and filter it into a version that
+ * is safe for output onto webpages. It achieves this by:
+ *
+ *  -# Lexing (parsing into tokens) the document,
+ *  -# Executing various strategies on the tokens:
+ *      -# Removing all elements not in the whitelist,
+ *      -# Making the tokens well-formed,
+ *      -# Fixing the nesting of the nodes, and
+ *      -# Validating attributes of the nodes; and
+ *  -# Generating HTML from the purified tokens.
+ *
+ * However, most users will only need to interface with the HTMLPurifier
+ * and HTMLPurifier_Config.
+ */
+
+/*
+    HTML Purifier 4.14.0 - Standards Compliant HTML Filtering
+    Copyright (C) 2006-2008 Edward Z. Yang
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+/**
+ * Facade that coordinates HTML Purifier's subsystems in order to purify HTML.
+ *
+ * @note There are several points in which configuration can be specified
+ *       for HTML Purifier.  The precedence of these (from lowest to
+ *       highest) is as follows:
+ *          -# Instance: new HTMLPurifier($config)
+ *          -# Invocation: purify($html, $config)
+ *       These configurations are entirely independent of each other and
+ *       are *not* merged (this behavior may change in the future).
+ *
+ * @todo We need an easier way to inject strategies using the configuration
+ *       object.
+ */
+class HTMLPurifier
+{
+
+    /**
+     * Version of HTML Purifier.
+     * @type string
+     */
+    public $version = '4.14.0';
+
+    /**
+     * Constant with version of HTML Purifier.
+     */
+    const VERSION = '4.14.0';
+
+    /**
+     * Global configuration object.
+     * @type HTMLPurifier_Config
+     */
+    public $config;
+
+    /**
+     * Array of extra filter objects to run on HTML,
+     * for backwards compatibility.
+     * @type HTMLPurifier_Filter[]
+     */
+    private $filters = array();
+
+    /**
+     * Single instance of HTML Purifier.
+     * @type HTMLPurifier
+     */
+    private static $instance;
+
+    /**
+     * @type HTMLPurifier_Strategy_Core
+     */
+    protected $strategy;
+
+    /**
+     * @type HTMLPurifier_Generator
+     */
+    protected $generator;
+
+    /**
+     * Resultant context of last run purification.
+     * Is an array of contexts if the last called method was purifyArray().
+     * @type HTMLPurifier_Context
+     */
+    public $context;
+
+    /**
+     * Initializes the purifier.
+     *
+     * @param HTMLPurifier_Config|mixed $config Optional HTMLPurifier_Config object
+     *                for all instances of the purifier, if omitted, a default
+     *                configuration is supplied (which can be overridden on a
+     *                per-use basis).
+     *                The parameter can also be any type that
+     *                HTMLPurifier_Config::create() supports.
+     */
+    public function __construct($config = null)
+    {
+        $this->config = HTMLPurifier_Config::create($config);
+        $this->strategy = new HTMLPurifier_Strategy_Core();
+    }
+
+    /**
+     * Adds a filter to process the output. First come first serve
+     *
+     * @param HTMLPurifier_Filter $filter HTMLPurifier_Filter object
+     */
+    public function addFilter($filter)
+    {
+        trigger_error(
+            'HTMLPurifier->addFilter() is deprecated, use configuration directives' .
+            ' in the Filter namespace or Filter.Custom',
+            E_USER_WARNING
+        );
+        $this->filters[] = $filter;
+    }
+
+    /**
+     * Filters an HTML snippet/document to be XSS-free and standards-compliant.
+     *
+     * @param string $html String of HTML to purify
+     * @param HTMLPurifier_Config $config Config object for this operation,
+     *                if omitted, defaults to the config object specified during this
+     *                object's construction. The parameter can also be any type
+     *                that HTMLPurifier_Config::create() supports.
+     *
+     * @return string Purified HTML
+     */
+    public function purify($html, $config = null)
+    {
+        // :TODO: make the config merge in, instead of replace
+        $config = $config ? HTMLPurifier_Config::create($config) : $this->config;
+
+        // implementation is partially environment dependant, partially
+        // configuration dependant
+        $lexer = HTMLPurifier_Lexer::create($config);
+
+        $context = new HTMLPurifier_Context();
+
+        // setup HTML generator
+        $this->generator = new HTMLPurifier_Generator($config, $context);
+        $context->register('Generator', $this->generator);
+
+        // set up global context variables
+        if ($config->get('Core.CollectErrors')) {
+            // may get moved out if other facilities use it
+            $language_factory = HTMLPurifier_LanguageFactory::instance();
+            $language = $language_factory->create($config, $context);
+            $context->register('Locale', $language);
+
+            $error_collector = new HTMLPurifier_ErrorCollector($context);
+            $context->register('ErrorCollector', $error_collector);
+        }
+
+        // setup id_accumulator context, necessary due to the fact that
+        // AttrValidator can be called from many places
+        $id_accumulator = HTMLPurifier_IDAccumulator::build($config, $context);
+        $context->register('IDAccumulator', $id_accumulator);
+
+        $html = HTMLPurifier_Encoder::convertToUTF8($html, $config, $context);
+
+        // setup filters
+        $filter_flags = $config->getBatch('Filter');
+        $custom_filters = $filter_flags['Custom'];
+        unset($filter_flags['Custom']);
+        $filters = array();
+        foreach ($filter_flags as $filter => $flag) {
+            if (!$flag) {
+                continue;
+            }
+            if (strpos($filter, '.') !== false) {
+                continue;
+            }
+            $class = "HTMLPurifier_Filter_$filter";
+            $filters[] = new $class;
+        }
+        foreach ($custom_filters as $filter) {
+            // maybe "HTMLPurifier_Filter_$filter", but be consistent with AutoFormat
+            $filters[] = $filter;
+        }
+        $filters = array_merge($filters, $this->filters);
+        // maybe prepare(), but later
+
+        for ($i = 0, $filter_size = count($filters); $i < $filter_size; $i++) {
+            $html = $filters[$i]->preFilter($html, $config, $context);
+        }
+
+        // purified HTML
+        $html =
+            $this->generator->generateFromTokens(
+                // list of tokens
+                $this->strategy->execute(
+                    // list of un-purified tokens
+                    $lexer->tokenizeHTML(
+                        // un-purified HTML
+                        $html,
+                        $config,
+                        $context
+                    ),
+                    $config,
+                    $context
+                )
+            );
+
+        for ($i = $filter_size - 1; $i >= 0; $i--) {
+            $html = $filters[$i]->postFilter($html, $config, $context);
+        }
+
+        $html = HTMLPurifier_Encoder::convertFromUTF8($html, $config, $context);
+        $this->context =& $context;
+        return $html;
+    }
+
+    /**
+     * Filters an array of HTML snippets
+     *
+     * @param string[] $array_of_html Array of html snippets
+     * @param HTMLPurifier_Config $config Optional config object for this operation.
+     *                See HTMLPurifier::purify() for more details.
+     *
+     * @return string[] Array of purified HTML
+     */
+    public function purifyArray($array_of_html, $config = null)
+    {
+        $context_array = array();
+        $array = array();
+        foreach($array_of_html as $key=>$value){
+            if (is_array($value)) {
+                $array[$key] = $this->purifyArray($value, $config);
+            } else {
+                $array[$key] = $this->purify($value, $config);
+            }
+            $context_array[$key] = $this->context;
+        }
+        $this->context = $context_array;
+        return $array;
+    }
+
+    /**
+     * Singleton for enforcing just one HTML Purifier in your system
+     *
+     * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype
+     *                   HTMLPurifier instance to overload singleton with,
+     *                   or HTMLPurifier_Config instance to configure the
+     *                   generated version with.
+     *
+     * @return HTMLPurifier
+     */
+    public static function instance($prototype = null)
+    {
+        if (!self::$instance || $prototype) {
+            if ($prototype instanceof HTMLPurifier) {
+                self::$instance = $prototype;
+            } elseif ($prototype) {
+                self::$instance = new HTMLPurifier($prototype);
+            } else {
+                self::$instance = new HTMLPurifier();
+            }
+        }
+        return self::$instance;
+    }
+
+    /**
+     * Singleton for enforcing just one HTML Purifier in your system
+     *
+     * @param HTMLPurifier|HTMLPurifier_Config $prototype Optional prototype
+     *                   HTMLPurifier instance to overload singleton with,
+     *                   or HTMLPurifier_Config instance to configure the
+     *                   generated version with.
+     *
+     * @return HTMLPurifier
+     * @note Backwards compatibility, see instance()
+     */
+    public static function getInstance($prototype = null)
+    {
+        return HTMLPurifier::instance($prototype);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 228 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier.safe-includes.php

@@ -0,0 +1,228 @@
+<?php
+
+/**
+ * @file
+ * This file was auto-generated by generate-includes.php and includes all of
+ * the core files required by HTML Purifier. This is a convenience stub that
+ * includes all files using dirname(__FILE__) and require_once. PLEASE DO NOT
+ * EDIT THIS FILE, changes will be overwritten the next time the script is run.
+ *
+ * Changes to include_path are not necessary.
+ */
+
+$__dir = dirname(__FILE__);
+
+require_once $__dir . '/HTMLPurifier.php';
+require_once $__dir . '/HTMLPurifier/Arborize.php';
+require_once $__dir . '/HTMLPurifier/AttrCollections.php';
+require_once $__dir . '/HTMLPurifier/AttrDef.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform.php';
+require_once $__dir . '/HTMLPurifier/AttrTypes.php';
+require_once $__dir . '/HTMLPurifier/AttrValidator.php';
+require_once $__dir . '/HTMLPurifier/Bootstrap.php';
+require_once $__dir . '/HTMLPurifier/Definition.php';
+require_once $__dir . '/HTMLPurifier/CSSDefinition.php';
+require_once $__dir . '/HTMLPurifier/ChildDef.php';
+require_once $__dir . '/HTMLPurifier/Config.php';
+require_once $__dir . '/HTMLPurifier/ConfigSchema.php';
+require_once $__dir . '/HTMLPurifier/ContentSets.php';
+require_once $__dir . '/HTMLPurifier/Context.php';
+require_once $__dir . '/HTMLPurifier/DefinitionCache.php';
+require_once $__dir . '/HTMLPurifier/DefinitionCacheFactory.php';
+require_once $__dir . '/HTMLPurifier/Doctype.php';
+require_once $__dir . '/HTMLPurifier/DoctypeRegistry.php';
+require_once $__dir . '/HTMLPurifier/ElementDef.php';
+require_once $__dir . '/HTMLPurifier/Encoder.php';
+require_once $__dir . '/HTMLPurifier/EntityLookup.php';
+require_once $__dir . '/HTMLPurifier/EntityParser.php';
+require_once $__dir . '/HTMLPurifier/ErrorCollector.php';
+require_once $__dir . '/HTMLPurifier/ErrorStruct.php';
+require_once $__dir . '/HTMLPurifier/Exception.php';
+require_once $__dir . '/HTMLPurifier/Filter.php';
+require_once $__dir . '/HTMLPurifier/Generator.php';
+require_once $__dir . '/HTMLPurifier/HTMLDefinition.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule.php';
+require_once $__dir . '/HTMLPurifier/HTMLModuleManager.php';
+require_once $__dir . '/HTMLPurifier/IDAccumulator.php';
+require_once $__dir . '/HTMLPurifier/Injector.php';
+require_once $__dir . '/HTMLPurifier/Language.php';
+require_once $__dir . '/HTMLPurifier/LanguageFactory.php';
+require_once $__dir . '/HTMLPurifier/Length.php';
+require_once $__dir . '/HTMLPurifier/Lexer.php';
+require_once $__dir . '/HTMLPurifier/Node.php';
+require_once $__dir . '/HTMLPurifier/PercentEncoder.php';
+require_once $__dir . '/HTMLPurifier/PropertyList.php';
+require_once $__dir . '/HTMLPurifier/PropertyListIterator.php';
+require_once $__dir . '/HTMLPurifier/Queue.php';
+require_once $__dir . '/HTMLPurifier/Strategy.php';
+require_once $__dir . '/HTMLPurifier/StringHash.php';
+require_once $__dir . '/HTMLPurifier/StringHashParser.php';
+require_once $__dir . '/HTMLPurifier/TagTransform.php';
+require_once $__dir . '/HTMLPurifier/Token.php';
+require_once $__dir . '/HTMLPurifier/TokenFactory.php';
+require_once $__dir . '/HTMLPurifier/URI.php';
+require_once $__dir . '/HTMLPurifier/URIDefinition.php';
+require_once $__dir . '/HTMLPurifier/URIFilter.php';
+require_once $__dir . '/HTMLPurifier/URIParser.php';
+require_once $__dir . '/HTMLPurifier/URIScheme.php';
+require_once $__dir . '/HTMLPurifier/URISchemeRegistry.php';
+require_once $__dir . '/HTMLPurifier/UnitConverter.php';
+require_once $__dir . '/HTMLPurifier/VarParser.php';
+require_once $__dir . '/HTMLPurifier/VarParserException.php';
+require_once $__dir . '/HTMLPurifier/Zipper.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/Clone.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/Enum.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/Integer.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/Lang.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/Switch.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/Text.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/URI.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Number.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/AlphaValue.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Background.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Border.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Color.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Composite.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Filter.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Font.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/FontFamily.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Ident.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Length.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/ListStyle.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Multiple.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/Percentage.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/TextDecoration.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/CSS/URI.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Bool.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Nmtokens.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Class.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Color.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/HTML/FrameTarget.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/HTML/ID.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Pixels.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/HTML/Length.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/HTML/LinkTypes.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/HTML/MultiLength.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/URI/Email.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/URI/Host.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/URI/IPv4.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/URI/IPv6.php';
+require_once $__dir . '/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/Background.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/BdoDir.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/BgColor.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/BoolToCSS.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/Border.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/EnumToCSS.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/ImgRequired.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/ImgSpace.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/Input.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/Lang.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/Length.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/Name.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/NameSync.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/Nofollow.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/SafeEmbed.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/SafeObject.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/SafeParam.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/ScriptRequired.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/TargetBlank.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/TargetNoopener.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/TargetNoreferrer.php';
+require_once $__dir . '/HTMLPurifier/AttrTransform/Textarea.php';
+require_once $__dir . '/HTMLPurifier/ChildDef/Chameleon.php';
+require_once $__dir . '/HTMLPurifier/ChildDef/Custom.php';
+require_once $__dir . '/HTMLPurifier/ChildDef/Empty.php';
+require_once $__dir . '/HTMLPurifier/ChildDef/List.php';
+require_once $__dir . '/HTMLPurifier/ChildDef/Required.php';
+require_once $__dir . '/HTMLPurifier/ChildDef/Optional.php';
+require_once $__dir . '/HTMLPurifier/ChildDef/StrictBlockquote.php';
+require_once $__dir . '/HTMLPurifier/ChildDef/Table.php';
+require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator.php';
+require_once $__dir . '/HTMLPurifier/DefinitionCache/Null.php';
+require_once $__dir . '/HTMLPurifier/DefinitionCache/Serializer.php';
+require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator/Cleanup.php';
+require_once $__dir . '/HTMLPurifier/DefinitionCache/Decorator/Memory.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Bdo.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/CommonAttributes.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Edit.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Forms.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Hypertext.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Iframe.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Image.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Legacy.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/List.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Name.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Nofollow.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/NonXMLCommonAttributes.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Object.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Presentation.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Proprietary.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Ruby.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/SafeEmbed.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/SafeObject.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/SafeScripting.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Scripting.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/StyleAttribute.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Tables.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Target.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/TargetBlank.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/TargetNoopener.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/TargetNoreferrer.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Text.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/XMLCommonAttributes.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Name.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Proprietary.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/XHTMLAndHTML4.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Strict.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/Transitional.php';
+require_once $__dir . '/HTMLPurifier/HTMLModule/Tidy/XHTML.php';
+require_once $__dir . '/HTMLPurifier/Injector/AutoParagraph.php';
+require_once $__dir . '/HTMLPurifier/Injector/DisplayLinkURI.php';
+require_once $__dir . '/HTMLPurifier/Injector/Linkify.php';
+require_once $__dir . '/HTMLPurifier/Injector/PurifierLinkify.php';
+require_once $__dir . '/HTMLPurifier/Injector/RemoveEmpty.php';
+require_once $__dir . '/HTMLPurifier/Injector/RemoveSpansWithoutAttributes.php';
+require_once $__dir . '/HTMLPurifier/Injector/SafeObject.php';
+require_once $__dir . '/HTMLPurifier/Lexer/DOMLex.php';
+require_once $__dir . '/HTMLPurifier/Lexer/DirectLex.php';
+require_once $__dir . '/HTMLPurifier/Node/Comment.php';
+require_once $__dir . '/HTMLPurifier/Node/Element.php';
+require_once $__dir . '/HTMLPurifier/Node/Text.php';
+require_once $__dir . '/HTMLPurifier/Strategy/Composite.php';
+require_once $__dir . '/HTMLPurifier/Strategy/Core.php';
+require_once $__dir . '/HTMLPurifier/Strategy/FixNesting.php';
+require_once $__dir . '/HTMLPurifier/Strategy/MakeWellFormed.php';
+require_once $__dir . '/HTMLPurifier/Strategy/RemoveForeignElements.php';
+require_once $__dir . '/HTMLPurifier/Strategy/ValidateAttributes.php';
+require_once $__dir . '/HTMLPurifier/TagTransform/Font.php';
+require_once $__dir . '/HTMLPurifier/TagTransform/Simple.php';
+require_once $__dir . '/HTMLPurifier/Token/Comment.php';
+require_once $__dir . '/HTMLPurifier/Token/Tag.php';
+require_once $__dir . '/HTMLPurifier/Token/Empty.php';
+require_once $__dir . '/HTMLPurifier/Token/End.php';
+require_once $__dir . '/HTMLPurifier/Token/Start.php';
+require_once $__dir . '/HTMLPurifier/Token/Text.php';
+require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternal.php';
+require_once $__dir . '/HTMLPurifier/URIFilter/DisableExternalResources.php';
+require_once $__dir . '/HTMLPurifier/URIFilter/DisableResources.php';
+require_once $__dir . '/HTMLPurifier/URIFilter/HostBlacklist.php';
+require_once $__dir . '/HTMLPurifier/URIFilter/MakeAbsolute.php';
+require_once $__dir . '/HTMLPurifier/URIFilter/Munge.php';
+require_once $__dir . '/HTMLPurifier/URIFilter/SafeIframe.php';
+require_once $__dir . '/HTMLPurifier/URIScheme/data.php';
+require_once $__dir . '/HTMLPurifier/URIScheme/file.php';
+require_once $__dir . '/HTMLPurifier/URIScheme/ftp.php';
+require_once $__dir . '/HTMLPurifier/URIScheme/http.php';
+require_once $__dir . '/HTMLPurifier/URIScheme/https.php';
+require_once $__dir . '/HTMLPurifier/URIScheme/mailto.php';
+require_once $__dir . '/HTMLPurifier/URIScheme/news.php';
+require_once $__dir . '/HTMLPurifier/URIScheme/nntp.php';
+require_once $__dir . '/HTMLPurifier/URIScheme/tel.php';
+require_once $__dir . '/HTMLPurifier/VarParser/Flexible.php';
+require_once $__dir . '/HTMLPurifier/VarParser/Native.php';

+ 71 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/Arborize.php

@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * Converts a stream of HTMLPurifier_Token into an HTMLPurifier_Node,
+ * and back again.
+ *
+ * @note This transformation is not an equivalence.  We mutate the input
+ * token stream to make it so; see all [MUT] markers in code.
+ */
+class HTMLPurifier_Arborize
+{
+    public static function arborize($tokens, $config, $context) {
+        $definition = $config->getHTMLDefinition();
+        $parent = new HTMLPurifier_Token_Start($definition->info_parent);
+        $stack = array($parent->toNode());
+        foreach ($tokens as $token) {
+            $token->skip = null; // [MUT]
+            $token->carryover = null; // [MUT]
+            if ($token instanceof HTMLPurifier_Token_End) {
+                $token->start = null; // [MUT]
+                $r = array_pop($stack);
+                //assert($r->name === $token->name);
+                //assert(empty($token->attr));
+                $r->endCol = $token->col;
+                $r->endLine = $token->line;
+                $r->endArmor = $token->armor;
+                continue;
+            }
+            $node = $token->toNode();
+            $stack[count($stack)-1]->children[] = $node;
+            if ($token instanceof HTMLPurifier_Token_Start) {
+                $stack[] = $node;
+            }
+        }
+        //assert(count($stack) == 1);
+        return $stack[0];
+    }
+
+    public static function flatten($node, $config, $context) {
+        $level = 0;
+        $nodes = array($level => new HTMLPurifier_Queue(array($node)));
+        $closingTokens = array();
+        $tokens = array();
+        do {
+            while (!$nodes[$level]->isEmpty()) {
+                $node = $nodes[$level]->shift(); // FIFO
+                list($start, $end) = $node->toTokenPair();
+                if ($level > 0) {
+                    $tokens[] = $start;
+                }
+                if ($end !== NULL) {
+                    $closingTokens[$level][] = $end;
+                }
+                if ($node instanceof HTMLPurifier_Node_Element) {
+                    $level++;
+                    $nodes[$level] = new HTMLPurifier_Queue();
+                    foreach ($node->children as $childNode) {
+                        $nodes[$level]->push($childNode);
+                    }
+                }
+            }
+            $level--;
+            if ($level && isset($closingTokens[$level])) {
+                while ($token = array_pop($closingTokens[$level])) {
+                    $tokens[] = $token;
+                }
+            }
+        } while ($level > 0);
+        return $tokens;
+    }
+}

+ 148 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrCollections.php

@@ -0,0 +1,148 @@
+<?php
+
+/**
+ * Defines common attribute collections that modules reference
+ */
+
+class HTMLPurifier_AttrCollections
+{
+
+    /**
+     * Associative array of attribute collections, indexed by name.
+     * @type array
+     */
+    public $info = array();
+
+    /**
+     * Performs all expansions on internal data for use by other inclusions
+     * It also collects all attribute collection extensions from
+     * modules
+     * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
+     * @param HTMLPurifier_HTMLModule[] $modules Hash array of HTMLPurifier_HTMLModule members
+     */
+    public function __construct($attr_types, $modules)
+    {
+        $this->doConstruct($attr_types, $modules);
+    }
+
+    public function doConstruct($attr_types, $modules)
+    {
+        // load extensions from the modules
+        foreach ($modules as $module) {
+            foreach ($module->attr_collections as $coll_i => $coll) {
+                if (!isset($this->info[$coll_i])) {
+                    $this->info[$coll_i] = array();
+                }
+                foreach ($coll as $attr_i => $attr) {
+                    if ($attr_i === 0 && isset($this->info[$coll_i][$attr_i])) {
+                        // merge in includes
+                        $this->info[$coll_i][$attr_i] = array_merge(
+                            $this->info[$coll_i][$attr_i],
+                            $attr
+                        );
+                        continue;
+                    }
+                    $this->info[$coll_i][$attr_i] = $attr;
+                }
+            }
+        }
+        // perform internal expansions and inclusions
+        foreach ($this->info as $name => $attr) {
+            // merge attribute collections that include others
+            $this->performInclusions($this->info[$name]);
+            // replace string identifiers with actual attribute objects
+            $this->expandIdentifiers($this->info[$name], $attr_types);
+        }
+    }
+
+    /**
+     * Takes a reference to an attribute associative array and performs
+     * all inclusions specified by the zero index.
+     * @param array &$attr Reference to attribute array
+     */
+    public function performInclusions(&$attr)
+    {
+        if (!isset($attr[0])) {
+            return;
+        }
+        $merge = $attr[0];
+        $seen  = array(); // recursion guard
+        // loop through all the inclusions
+        for ($i = 0; isset($merge[$i]); $i++) {
+            if (isset($seen[$merge[$i]])) {
+                continue;
+            }
+            $seen[$merge[$i]] = true;
+            // foreach attribute of the inclusion, copy it over
+            if (!isset($this->info[$merge[$i]])) {
+                continue;
+            }
+            foreach ($this->info[$merge[$i]] as $key => $value) {
+                if (isset($attr[$key])) {
+                    continue;
+                } // also catches more inclusions
+                $attr[$key] = $value;
+            }
+            if (isset($this->info[$merge[$i]][0])) {
+                // recursion
+                $merge = array_merge($merge, $this->info[$merge[$i]][0]);
+            }
+        }
+        unset($attr[0]);
+    }
+
+    /**
+     * Expands all string identifiers in an attribute array by replacing
+     * them with the appropriate values inside HTMLPurifier_AttrTypes
+     * @param array &$attr Reference to attribute array
+     * @param HTMLPurifier_AttrTypes $attr_types HTMLPurifier_AttrTypes instance
+     */
+    public function expandIdentifiers(&$attr, $attr_types)
+    {
+        // because foreach will process new elements we add, make sure we
+        // skip duplicates
+        $processed = array();
+
+        foreach ($attr as $def_i => $def) {
+            // skip inclusions
+            if ($def_i === 0) {
+                continue;
+            }
+
+            if (isset($processed[$def_i])) {
+                continue;
+            }
+
+            // determine whether or not attribute is required
+            if ($required = (strpos($def_i, '*') !== false)) {
+                // rename the definition
+                unset($attr[$def_i]);
+                $def_i = trim($def_i, '*');
+                $attr[$def_i] = $def;
+            }
+
+            $processed[$def_i] = true;
+
+            // if we've already got a literal object, move on
+            if (is_object($def)) {
+                // preserve previous required
+                $attr[$def_i]->required = ($required || $attr[$def_i]->required);
+                continue;
+            }
+
+            if ($def === false) {
+                unset($attr[$def_i]);
+                continue;
+            }
+
+            if ($t = $attr_types->get($def)) {
+                $attr[$def_i] = $t;
+                $attr[$def_i]->required = $required;
+            } else {
+                unset($attr[$def_i]);
+            }
+        }
+    }
+}
+
+// vim: et sw=4 sts=4

+ 144 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef.php

@@ -0,0 +1,144 @@
+<?php
+
+/**
+ * Base class for all validating attribute definitions.
+ *
+ * This family of classes forms the core for not only HTML attribute validation,
+ * but also any sort of string that needs to be validated or cleaned (which
+ * means CSS properties and composite definitions are defined here too).
+ * Besides defining (through code) what precisely makes the string valid,
+ * subclasses are also responsible for cleaning the code if possible.
+ */
+
+abstract class HTMLPurifier_AttrDef
+{
+
+    /**
+     * Tells us whether or not an HTML attribute is minimized.
+     * Has no meaning in other contexts.
+     * @type bool
+     */
+    public $minimized = false;
+
+    /**
+     * Tells us whether or not an HTML attribute is required.
+     * Has no meaning in other contexts
+     * @type bool
+     */
+    public $required = false;
+
+    /**
+     * Validates and cleans passed string according to a definition.
+     *
+     * @param string $string String to be validated and cleaned.
+     * @param HTMLPurifier_Config $config Mandatory HTMLPurifier_Config object.
+     * @param HTMLPurifier_Context $context Mandatory HTMLPurifier_Context object.
+     */
+    abstract public function validate($string, $config, $context);
+
+    /**
+     * Convenience method that parses a string as if it were CDATA.
+     *
+     * This method process a string in the manner specified at
+     * <http://www.w3.org/TR/html4/types.html#h-6.2> by removing
+     * leading and trailing whitespace, ignoring line feeds, and replacing
+     * carriage returns and tabs with spaces.  While most useful for HTML
+     * attributes specified as CDATA, it can also be applied to most CSS
+     * values.
+     *
+     * @note This method is not entirely standards compliant, as trim() removes
+     *       more types of whitespace than specified in the spec. In practice,
+     *       this is rarely a problem, as those extra characters usually have
+     *       already been removed by HTMLPurifier_Encoder.
+     *
+     * @warning This processing is inconsistent with XML's whitespace handling
+     *          as specified by section 3.3.3 and referenced XHTML 1.0 section
+     *          4.7.  However, note that we are NOT necessarily
+     *          parsing XML, thus, this behavior may still be correct. We
+     *          assume that newlines have been normalized.
+     */
+    public function parseCDATA($string)
+    {
+        $string = trim($string);
+        $string = str_replace(array("\n", "\t", "\r"), ' ', $string);
+        return $string;
+    }
+
+    /**
+     * Factory method for creating this class from a string.
+     * @param string $string String construction info
+     * @return HTMLPurifier_AttrDef Created AttrDef object corresponding to $string
+     */
+    public function make($string)
+    {
+        // default implementation, return a flyweight of this object.
+        // If $string has an effect on the returned object (i.e. you
+        // need to overload this method), it is best
+        // to clone or instantiate new copies. (Instantiation is safer.)
+        return $this;
+    }
+
+    /**
+     * Removes spaces from rgb(0, 0, 0) so that shorthand CSS properties work
+     * properly. THIS IS A HACK!
+     * @param string $string a CSS colour definition
+     * @return string
+     */
+    protected function mungeRgb($string)
+    {
+        $p = '\s*(\d+(\.\d+)?([%]?))\s*';
+
+        if (preg_match('/(rgba|hsla)\(/', $string)) {
+            return preg_replace('/(rgba|hsla)\('.$p.','.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8,\11)', $string);
+        }
+
+        return preg_replace('/(rgb|hsl)\('.$p.','.$p.','.$p.'\)/', '\1(\2,\5,\8)', $string);
+    }
+
+    /**
+     * Parses a possibly escaped CSS string and returns the "pure"
+     * version of it.
+     */
+    protected function expandCSSEscape($string)
+    {
+        // flexibly parse it
+        $ret = '';
+        for ($i = 0, $c = strlen($string); $i < $c; $i++) {
+            if ($string[$i] === '\\') {
+                $i++;
+                if ($i >= $c) {
+                    $ret .= '\\';
+                    break;
+                }
+                if (ctype_xdigit($string[$i])) {
+                    $code = $string[$i];
+                    for ($a = 1, $i++; $i < $c && $a < 6; $i++, $a++) {
+                        if (!ctype_xdigit($string[$i])) {
+                            break;
+                        }
+                        $code .= $string[$i];
+                    }
+                    // We have to be extremely careful when adding
+                    // new characters, to make sure we're not breaking
+                    // the encoding.
+                    $char = HTMLPurifier_Encoder::unichr(hexdec($code));
+                    if (HTMLPurifier_Encoder::cleanUTF8($char) === '') {
+                        continue;
+                    }
+                    $ret .= $char;
+                    if ($i < $c && trim($string[$i]) !== '') {
+                        $i--;
+                    }
+                    continue;
+                }
+                if ($string[$i] === "\n") {
+                    continue;
+                }
+            }
+            $ret .= $string[$i];
+        }
+        return $ret;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 136 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS.php

@@ -0,0 +1,136 @@
+<?php
+
+/**
+ * Validates the HTML attribute style, otherwise known as CSS.
+ * @note We don't implement the whole CSS specification, so it might be
+ *       difficult to reuse this component in the context of validating
+ *       actual stylesheet declarations.
+ * @note If we were really serious about validating the CSS, we would
+ *       tokenize the styles and then parse the tokens. Obviously, we
+ *       are not doing that. Doing that could seriously harm performance,
+ *       but would make these components a lot more viable for a CSS
+ *       filtering solution.
+ */
+class HTMLPurifier_AttrDef_CSS extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @param string $css
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($css, $config, $context)
+    {
+        $css = $this->parseCDATA($css);
+
+        $definition = $config->getCSSDefinition();
+        $allow_duplicates = $config->get("CSS.AllowDuplicates");
+
+
+        // According to the CSS2.1 spec, the places where a
+        // non-delimiting semicolon can appear are in strings
+        // escape sequences.   So here is some dumb hack to
+        // handle quotes.
+        $len = strlen($css);
+        $accum = "";
+        $declarations = array();
+        $quoted = false;
+        for ($i = 0; $i < $len; $i++) {
+            $c = strcspn($css, ";'\"", $i);
+            $accum .= substr($css, $i, $c);
+            $i += $c;
+            if ($i == $len) break;
+            $d = $css[$i];
+            if ($quoted) {
+                $accum .= $d;
+                if ($d == $quoted) {
+                    $quoted = false;
+                }
+            } else {
+                if ($d == ";") {
+                    $declarations[] = $accum;
+                    $accum = "";
+                } else {
+                    $accum .= $d;
+                    $quoted = $d;
+                }
+            }
+        }
+        if ($accum != "") $declarations[] = $accum;
+
+        $propvalues = array();
+        $new_declarations = '';
+
+        /**
+         * Name of the current CSS property being validated.
+         */
+        $property = false;
+        $context->register('CurrentCSSProperty', $property);
+
+        foreach ($declarations as $declaration) {
+            if (!$declaration) {
+                continue;
+            }
+            if (!strpos($declaration, ':')) {
+                continue;
+            }
+            list($property, $value) = explode(':', $declaration, 2);
+            $property = trim($property);
+            $value = trim($value);
+            $ok = false;
+            do {
+                if (isset($definition->info[$property])) {
+                    $ok = true;
+                    break;
+                }
+                if (ctype_lower($property)) {
+                    break;
+                }
+                $property = strtolower($property);
+                if (isset($definition->info[$property])) {
+                    $ok = true;
+                    break;
+                }
+            } while (0);
+            if (!$ok) {
+                continue;
+            }
+            // inefficient call, since the validator will do this again
+            if (strtolower(trim($value)) !== 'inherit') {
+                // inherit works for everything (but only on the base property)
+                $result = $definition->info[$property]->validate(
+                    $value,
+                    $config,
+                    $context
+                );
+            } else {
+                $result = 'inherit';
+            }
+            if ($result === false) {
+                continue;
+            }
+            if ($allow_duplicates) {
+                $new_declarations .= "$property:$result;";
+            } else {
+                $propvalues[$property] = $result;
+            }
+        }
+
+        $context->destroy('CurrentCSSProperty');
+
+        // procedure does not write the new CSS simultaneously, so it's
+        // slightly inefficient, but it's the only way of getting rid of
+        // duplicates. Perhaps config to optimize it, but not now.
+
+        foreach ($propvalues as $prop => $value) {
+            $new_declarations .= "$prop:$value;";
+        }
+
+        return $new_declarations ? $new_declarations : false;
+
+    }
+
+}
+
+// vim: et sw=4 sts=4

+ 34 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/AlphaValue.php

@@ -0,0 +1,34 @@
+<?php
+
+class HTMLPurifier_AttrDef_CSS_AlphaValue extends HTMLPurifier_AttrDef_CSS_Number
+{
+
+    public function __construct()
+    {
+        parent::__construct(false); // opacity is non-negative, but we will clamp it
+    }
+
+    /**
+     * @param string $number
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return string
+     */
+    public function validate($number, $config, $context)
+    {
+        $result = parent::validate($number, $config, $context);
+        if ($result === false) {
+            return $result;
+        }
+        $float = (float)$result;
+        if ($float < 0.0) {
+            $result = '0';
+        }
+        if ($float > 1.0) {
+            $result = '1';
+        }
+        return $result;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 113 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Background.php

@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * Validates shorthand CSS property background.
+ * @warning Does not support url tokens that have internal spaces.
+ */
+class HTMLPurifier_AttrDef_CSS_Background extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * Local copy of component validators.
+     * @type HTMLPurifier_AttrDef[]
+     * @note See HTMLPurifier_AttrDef_Font::$info for a similar impl.
+     */
+    protected $info;
+
+    /**
+     * @param HTMLPurifier_Config $config
+     */
+    public function __construct($config)
+    {
+        $def = $config->getCSSDefinition();
+        $this->info['background-color'] = $def->info['background-color'];
+        $this->info['background-image'] = $def->info['background-image'];
+        $this->info['background-repeat'] = $def->info['background-repeat'];
+        $this->info['background-attachment'] = $def->info['background-attachment'];
+        $this->info['background-position'] = $def->info['background-position'];
+        $this->info['background-size'] = $def->info['background-size'];
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        // regular pre-processing
+        $string = $this->parseCDATA($string);
+        if ($string === '') {
+            return false;
+        }
+
+        // munge rgb() decl if necessary
+        $string = $this->mungeRgb($string);
+
+        // assumes URI doesn't have spaces in it
+        $bits = explode(' ', $string); // bits to process
+
+        $caught = array();
+        $caught['color'] = false;
+        $caught['image'] = false;
+        $caught['repeat'] = false;
+        $caught['attachment'] = false;
+        $caught['position'] = false;
+        $caught['size'] = false;
+
+        $i = 0; // number of catches
+
+        foreach ($bits as $bit) {
+            if ($bit === '') {
+                continue;
+            }
+            foreach ($caught as $key => $status) {
+                if ($key != 'position') {
+                    if ($status !== false) {
+                        continue;
+                    }
+                    $r = $this->info['background-' . $key]->validate($bit, $config, $context);
+                } else {
+                    $r = $bit;
+                }
+                if ($r === false) {
+                    continue;
+                }
+                if ($key == 'position') {
+                    if ($caught[$key] === false) {
+                        $caught[$key] = '';
+                    }
+                    $caught[$key] .= $r . ' ';
+                } else {
+                    $caught[$key] = $r;
+                }
+                $i++;
+                break;
+            }
+        }
+
+        if (!$i) {
+            return false;
+        }
+        if ($caught['position'] !== false) {
+            $caught['position'] = $this->info['background-position']->
+                validate($caught['position'], $config, $context);
+        }
+
+        $ret = array();
+        foreach ($caught as $value) {
+            if ($value === false) {
+                continue;
+            }
+            $ret[] = $value;
+        }
+
+        if (empty($ret)) {
+            return false;
+        }
+        return implode(' ', $ret);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 157 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/BackgroundPosition.php

@@ -0,0 +1,157 @@
+<?php
+
+/* W3C says:
+    [ // adjective and number must be in correct order, even if
+      // you could switch them without introducing ambiguity.
+      // some browsers support that syntax
+        [
+            <percentage> | <length> | left | center | right
+        ]
+        [
+            <percentage> | <length> | top | center | bottom
+        ]?
+    ] |
+    [ // this signifies that the vertical and horizontal adjectives
+      // can be arbitrarily ordered, however, there can only be two,
+      // one of each, or none at all
+        [
+            left | center | right
+        ] ||
+        [
+            top | center | bottom
+        ]
+    ]
+    top, left = 0%
+    center, (none) = 50%
+    bottom, right = 100%
+*/
+
+/* QuirksMode says:
+    keyword + length/percentage must be ordered correctly, as per W3C
+
+    Internet Explorer and Opera, however, support arbitrary ordering. We
+    should fix it up.
+
+    Minor issue though, not strictly necessary.
+*/
+
+// control freaks may appreciate the ability to convert these to
+// percentages or something, but it's not necessary
+
+/**
+ * Validates the value of background-position.
+ */
+class HTMLPurifier_AttrDef_CSS_BackgroundPosition extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @type HTMLPurifier_AttrDef_CSS_Length
+     */
+    protected $length;
+
+    /**
+     * @type HTMLPurifier_AttrDef_CSS_Percentage
+     */
+    protected $percentage;
+
+    public function __construct()
+    {
+        $this->length = new HTMLPurifier_AttrDef_CSS_Length();
+        $this->percentage = new HTMLPurifier_AttrDef_CSS_Percentage();
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = $this->parseCDATA($string);
+        $bits = explode(' ', $string);
+
+        $keywords = array();
+        $keywords['h'] = false; // left, right
+        $keywords['v'] = false; // top, bottom
+        $keywords['ch'] = false; // center (first word)
+        $keywords['cv'] = false; // center (second word)
+        $measures = array();
+
+        $i = 0;
+
+        $lookup = array(
+            'top' => 'v',
+            'bottom' => 'v',
+            'left' => 'h',
+            'right' => 'h',
+            'center' => 'c'
+        );
+
+        foreach ($bits as $bit) {
+            if ($bit === '') {
+                continue;
+            }
+
+            // test for keyword
+            $lbit = ctype_lower($bit) ? $bit : strtolower($bit);
+            if (isset($lookup[$lbit])) {
+                $status = $lookup[$lbit];
+                if ($status == 'c') {
+                    if ($i == 0) {
+                        $status = 'ch';
+                    } else {
+                        $status = 'cv';
+                    }
+                }
+                $keywords[$status] = $lbit;
+                $i++;
+            }
+
+            // test for length
+            $r = $this->length->validate($bit, $config, $context);
+            if ($r !== false) {
+                $measures[] = $r;
+                $i++;
+            }
+
+            // test for percentage
+            $r = $this->percentage->validate($bit, $config, $context);
+            if ($r !== false) {
+                $measures[] = $r;
+                $i++;
+            }
+        }
+
+        if (!$i) {
+            return false;
+        } // no valid values were caught
+
+        $ret = array();
+
+        // first keyword
+        if ($keywords['h']) {
+            $ret[] = $keywords['h'];
+        } elseif ($keywords['ch']) {
+            $ret[] = $keywords['ch'];
+            $keywords['cv'] = false; // prevent re-use: center = center center
+        } elseif (count($measures)) {
+            $ret[] = array_shift($measures);
+        }
+
+        if ($keywords['v']) {
+            $ret[] = $keywords['v'];
+        } elseif ($keywords['cv']) {
+            $ret[] = $keywords['cv'];
+        } elseif (count($measures)) {
+            $ret[] = array_shift($measures);
+        }
+
+        if (empty($ret)) {
+            return false;
+        }
+        return implode(' ', $ret);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 56 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Border.php

@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * Validates the border property as defined by CSS.
+ */
+class HTMLPurifier_AttrDef_CSS_Border extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * Local copy of properties this property is shorthand for.
+     * @type HTMLPurifier_AttrDef[]
+     */
+    protected $info = array();
+
+    /**
+     * @param HTMLPurifier_Config $config
+     */
+    public function __construct($config)
+    {
+        $def = $config->getCSSDefinition();
+        $this->info['border-width'] = $def->info['border-width'];
+        $this->info['border-style'] = $def->info['border-style'];
+        $this->info['border-top-color'] = $def->info['border-top-color'];
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = $this->parseCDATA($string);
+        $string = $this->mungeRgb($string);
+        $bits = explode(' ', $string);
+        $done = array(); // segments we've finished
+        $ret = ''; // return value
+        foreach ($bits as $bit) {
+            foreach ($this->info as $propname => $validator) {
+                if (isset($done[$propname])) {
+                    continue;
+                }
+                $r = $validator->validate($bit, $config, $context);
+                if ($r !== false) {
+                    $ret .= $r . ' ';
+                    $done[$propname] = true;
+                    break;
+                }
+            }
+        }
+        return rtrim($ret);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 161 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Color.php

@@ -0,0 +1,161 @@
+<?php
+
+/**
+ * Validates Color as defined by CSS.
+ */
+class HTMLPurifier_AttrDef_CSS_Color extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @type HTMLPurifier_AttrDef_CSS_AlphaValue
+     */
+    protected $alpha;
+
+    public function __construct()
+    {
+        $this->alpha = new HTMLPurifier_AttrDef_CSS_AlphaValue();
+    }
+
+    /**
+     * @param string $color
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($color, $config, $context)
+    {
+        static $colors = null;
+        if ($colors === null) {
+            $colors = $config->get('Core.ColorKeywords');
+        }
+
+        $color = trim($color);
+        if ($color === '') {
+            return false;
+        }
+
+        $lower = strtolower($color);
+        if (isset($colors[$lower])) {
+            return $colors[$lower];
+        }
+
+        if (preg_match('#(rgb|rgba|hsl|hsla)\(#', $color, $matches) === 1) {
+            $length = strlen($color);
+            if (strpos($color, ')') !== $length - 1) {
+                return false;
+            }
+
+            // get used function : rgb, rgba, hsl or hsla
+            $function = $matches[1];
+
+            $parameters_size = 3;
+            $alpha_channel = false;
+            if (substr($function, -1) === 'a') {
+                $parameters_size = 4;
+                $alpha_channel = true;
+            }
+
+            /*
+             * Allowed types for values :
+             * parameter_position => [type => max_value]
+             */
+            $allowed_types = array(
+                1 => array('percentage' => 100, 'integer' => 255),
+                2 => array('percentage' => 100, 'integer' => 255),
+                3 => array('percentage' => 100, 'integer' => 255),
+            );
+            $allow_different_types = false;
+
+            if (strpos($function, 'hsl') !== false) {
+                $allowed_types = array(
+                    1 => array('integer' => 360),
+                    2 => array('percentage' => 100),
+                    3 => array('percentage' => 100),
+                );
+                $allow_different_types = true;
+            }
+
+            $values = trim(str_replace($function, '', $color), ' ()');
+
+            $parts = explode(',', $values);
+            if (count($parts) !== $parameters_size) {
+                return false;
+            }
+
+            $type = false;
+            $new_parts = array();
+            $i = 0;
+
+            foreach ($parts as $part) {
+                $i++;
+                $part = trim($part);
+
+                if ($part === '') {
+                    return false;
+                }
+
+                // different check for alpha channel
+                if ($alpha_channel === true && $i === count($parts)) {
+                    $result = $this->alpha->validate($part, $config, $context);
+
+                    if ($result === false) {
+                        return false;
+                    }
+
+                    $new_parts[] = (string)$result;
+                    continue;
+                }
+
+                if (substr($part, -1) === '%') {
+                    $current_type = 'percentage';
+                } else {
+                    $current_type = 'integer';
+                }
+
+                if (!array_key_exists($current_type, $allowed_types[$i])) {
+                    return false;
+                }
+
+                if (!$type) {
+                    $type = $current_type;
+                }
+
+                if ($allow_different_types === false && $type != $current_type) {
+                    return false;
+                }
+
+                $max_value = $allowed_types[$i][$current_type];
+
+                if ($current_type == 'integer') {
+                    // Return value between range 0 -> $max_value
+                    $new_parts[] = (int)max(min($part, $max_value), 0);
+                } elseif ($current_type == 'percentage') {
+                    $new_parts[] = (float)max(min(rtrim($part, '%'), $max_value), 0) . '%';
+                }
+            }
+
+            $new_values = implode(',', $new_parts);
+
+            $color = $function . '(' . $new_values . ')';
+        } else {
+            // hexadecimal handling
+            if ($color[0] === '#') {
+                $hex = substr($color, 1);
+            } else {
+                $hex = $color;
+                $color = '#' . $color;
+            }
+            $length = strlen($hex);
+            if ($length !== 3 && $length !== 6) {
+                return false;
+            }
+            if (!ctype_xdigit($hex)) {
+                return false;
+            }
+        }
+        return $color;
+    }
+
+}
+
+// vim: et sw=4 sts=4

+ 48 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Composite.php

@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * Allows multiple validators to attempt to validate attribute.
+ *
+ * Composite is just what it sounds like: a composite of many validators.
+ * This means that multiple HTMLPurifier_AttrDef objects will have a whack
+ * at the string.  If one of them passes, that's what is returned.  This is
+ * especially useful for CSS values, which often are a choice between
+ * an enumerated set of predefined values or a flexible data type.
+ */
+class HTMLPurifier_AttrDef_CSS_Composite extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * List of objects that may process strings.
+     * @type HTMLPurifier_AttrDef[]
+     * @todo Make protected
+     */
+    public $defs;
+
+    /**
+     * @param HTMLPurifier_AttrDef[] $defs List of HTMLPurifier_AttrDef objects
+     */
+    public function __construct($defs)
+    {
+        $this->defs = $defs;
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        foreach ($this->defs as $i => $def) {
+            $result = $this->defs[$i]->validate($string, $config, $context);
+            if ($result !== false) {
+                return $result;
+            }
+        }
+        return false;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 44 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/DenyElementDecorator.php

@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * Decorator which enables CSS properties to be disabled for specific elements.
+ */
+class HTMLPurifier_AttrDef_CSS_DenyElementDecorator extends HTMLPurifier_AttrDef
+{
+    /**
+     * @type HTMLPurifier_AttrDef
+     */
+    public $def;
+    /**
+     * @type string
+     */
+    public $element;
+
+    /**
+     * @param HTMLPurifier_AttrDef $def Definition to wrap
+     * @param string $element Element to deny
+     */
+    public function __construct($def, $element)
+    {
+        $this->def = $def;
+        $this->element = $element;
+    }
+
+    /**
+     * Checks if CurrentToken is set and equal to $this->element
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $token = $context->get('CurrentToken', true);
+        if ($token && $token->name == $this->element) {
+            return false;
+        }
+        return $this->def->validate($string, $config, $context);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 77 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Filter.php

@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * Microsoft's proprietary filter: CSS property
+ * @note Currently supports the alpha filter. In the future, this will
+ *       probably need an extensible framework
+ */
+class HTMLPurifier_AttrDef_CSS_Filter extends HTMLPurifier_AttrDef
+{
+    /**
+     * @type HTMLPurifier_AttrDef_Integer
+     */
+    protected $intValidator;
+
+    public function __construct()
+    {
+        $this->intValidator = new HTMLPurifier_AttrDef_Integer();
+    }
+
+    /**
+     * @param string $value
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($value, $config, $context)
+    {
+        $value = $this->parseCDATA($value);
+        if ($value === 'none') {
+            return $value;
+        }
+        // if we looped this we could support multiple filters
+        $function_length = strcspn($value, '(');
+        $function = trim(substr($value, 0, $function_length));
+        if ($function !== 'alpha' &&
+            $function !== 'Alpha' &&
+            $function !== 'progid:DXImageTransform.Microsoft.Alpha'
+        ) {
+            return false;
+        }
+        $cursor = $function_length + 1;
+        $parameters_length = strcspn($value, ')', $cursor);
+        $parameters = substr($value, $cursor, $parameters_length);
+        $params = explode(',', $parameters);
+        $ret_params = array();
+        $lookup = array();
+        foreach ($params as $param) {
+            list($key, $value) = explode('=', $param);
+            $key = trim($key);
+            $value = trim($value);
+            if (isset($lookup[$key])) {
+                continue;
+            }
+            if ($key !== 'opacity') {
+                continue;
+            }
+            $value = $this->intValidator->validate($value, $config, $context);
+            if ($value === false) {
+                continue;
+            }
+            $int = (int)$value;
+            if ($int > 100) {
+                $value = '100';
+            }
+            if ($int < 0) {
+                $value = '0';
+            }
+            $ret_params[] = "$key=$value";
+            $lookup[$key] = true;
+        }
+        $ret_parameters = implode(',', $ret_params);
+        $ret_function = "$function($ret_parameters)";
+        return $ret_function;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 176 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Font.php

@@ -0,0 +1,176 @@
+<?php
+
+/**
+ * Validates shorthand CSS property font.
+ */
+class HTMLPurifier_AttrDef_CSS_Font extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * Local copy of validators
+     * @type HTMLPurifier_AttrDef[]
+     * @note If we moved specific CSS property definitions to their own
+     *       classes instead of having them be assembled at run time by
+     *       CSSDefinition, this wouldn't be necessary.  We'd instantiate
+     *       our own copies.
+     */
+    protected $info = array();
+
+    /**
+     * @param HTMLPurifier_Config $config
+     */
+    public function __construct($config)
+    {
+        $def = $config->getCSSDefinition();
+        $this->info['font-style'] = $def->info['font-style'];
+        $this->info['font-variant'] = $def->info['font-variant'];
+        $this->info['font-weight'] = $def->info['font-weight'];
+        $this->info['font-size'] = $def->info['font-size'];
+        $this->info['line-height'] = $def->info['line-height'];
+        $this->info['font-family'] = $def->info['font-family'];
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        static $system_fonts = array(
+            'caption' => true,
+            'icon' => true,
+            'menu' => true,
+            'message-box' => true,
+            'small-caption' => true,
+            'status-bar' => true
+        );
+
+        // regular pre-processing
+        $string = $this->parseCDATA($string);
+        if ($string === '') {
+            return false;
+        }
+
+        // check if it's one of the keywords
+        $lowercase_string = strtolower($string);
+        if (isset($system_fonts[$lowercase_string])) {
+            return $lowercase_string;
+        }
+
+        $bits = explode(' ', $string); // bits to process
+        $stage = 0; // this indicates what we're looking for
+        $caught = array(); // which stage 0 properties have we caught?
+        $stage_1 = array('font-style', 'font-variant', 'font-weight');
+        $final = ''; // output
+
+        for ($i = 0, $size = count($bits); $i < $size; $i++) {
+            if ($bits[$i] === '') {
+                continue;
+            }
+            switch ($stage) {
+                case 0: // attempting to catch font-style, font-variant or font-weight
+                    foreach ($stage_1 as $validator_name) {
+                        if (isset($caught[$validator_name])) {
+                            continue;
+                        }
+                        $r = $this->info[$validator_name]->validate(
+                            $bits[$i],
+                            $config,
+                            $context
+                        );
+                        if ($r !== false) {
+                            $final .= $r . ' ';
+                            $caught[$validator_name] = true;
+                            break;
+                        }
+                    }
+                    // all three caught, continue on
+                    if (count($caught) >= 3) {
+                        $stage = 1;
+                    }
+                    if ($r !== false) {
+                        break;
+                    }
+                case 1: // attempting to catch font-size and perhaps line-height
+                    $found_slash = false;
+                    if (strpos($bits[$i], '/') !== false) {
+                        list($font_size, $line_height) =
+                            explode('/', $bits[$i]);
+                        if ($line_height === '') {
+                            // ooh, there's a space after the slash!
+                            $line_height = false;
+                            $found_slash = true;
+                        }
+                    } else {
+                        $font_size = $bits[$i];
+                        $line_height = false;
+                    }
+                    $r = $this->info['font-size']->validate(
+                        $font_size,
+                        $config,
+                        $context
+                    );
+                    if ($r !== false) {
+                        $final .= $r;
+                        // attempt to catch line-height
+                        if ($line_height === false) {
+                            // we need to scroll forward
+                            for ($j = $i + 1; $j < $size; $j++) {
+                                if ($bits[$j] === '') {
+                                    continue;
+                                }
+                                if ($bits[$j] === '/') {
+                                    if ($found_slash) {
+                                        return false;
+                                    } else {
+                                        $found_slash = true;
+                                        continue;
+                                    }
+                                }
+                                $line_height = $bits[$j];
+                                break;
+                            }
+                        } else {
+                            // slash already found
+                            $found_slash = true;
+                            $j = $i;
+                        }
+                        if ($found_slash) {
+                            $i = $j;
+                            $r = $this->info['line-height']->validate(
+                                $line_height,
+                                $config,
+                                $context
+                            );
+                            if ($r !== false) {
+                                $final .= '/' . $r;
+                            }
+                        }
+                        $final .= ' ';
+                        $stage = 2;
+                        break;
+                    }
+                    return false;
+                case 2: // attempting to catch font-family
+                    $font_family =
+                        implode(' ', array_slice($bits, $i, $size - $i));
+                    $r = $this->info['font-family']->validate(
+                        $font_family,
+                        $config,
+                        $context
+                    );
+                    if ($r !== false) {
+                        $final .= $r . ' ';
+                        // processing completed successfully
+                        return rtrim($final);
+                    }
+                    return false;
+            }
+        }
+        return false;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 219 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/FontFamily.php

@@ -0,0 +1,219 @@
+<?php
+
+/**
+ * Validates a font family list according to CSS spec
+ */
+class HTMLPurifier_AttrDef_CSS_FontFamily extends HTMLPurifier_AttrDef
+{
+
+    protected $mask = null;
+
+    public function __construct()
+    {
+        $this->mask = '_- ';
+        for ($c = 'a'; $c <= 'z'; $c++) {
+            $this->mask .= $c;
+        }
+        for ($c = 'A'; $c <= 'Z'; $c++) {
+            $this->mask .= $c;
+        }
+        for ($c = '0'; $c <= '9'; $c++) {
+            $this->mask .= $c;
+        } // cast-y, but should be fine
+        // special bytes used by UTF-8
+        for ($i = 0x80; $i <= 0xFF; $i++) {
+            // We don't bother excluding invalid bytes in this range,
+            // because the our restriction of well-formed UTF-8 will
+            // prevent these from ever occurring.
+            $this->mask .= chr($i);
+        }
+
+        /*
+            PHP's internal strcspn implementation is
+            O(length of string * length of mask), making it inefficient
+            for large masks.  However, it's still faster than
+            preg_match 8)
+          for (p = s1;;) {
+            spanp = s2;
+            do {
+              if (*spanp == c || p == s1_end) {
+                return p - s1;
+              }
+            } while (spanp++ < (s2_end - 1));
+            c = *++p;
+          }
+         */
+        // possible optimization: invert the mask.
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        static $generic_names = array(
+            'serif' => true,
+            'sans-serif' => true,
+            'monospace' => true,
+            'fantasy' => true,
+            'cursive' => true
+        );
+        $allowed_fonts = $config->get('CSS.AllowedFonts');
+
+        // assume that no font names contain commas in them
+        $fonts = explode(',', $string);
+        $final = '';
+        foreach ($fonts as $font) {
+            $font = trim($font);
+            if ($font === '') {
+                continue;
+            }
+            // match a generic name
+            if (isset($generic_names[$font])) {
+                if ($allowed_fonts === null || isset($allowed_fonts[$font])) {
+                    $final .= $font . ', ';
+                }
+                continue;
+            }
+            // match a quoted name
+            if ($font[0] === '"' || $font[0] === "'") {
+                $length = strlen($font);
+                if ($length <= 2) {
+                    continue;
+                }
+                $quote = $font[0];
+                if ($font[$length - 1] !== $quote) {
+                    continue;
+                }
+                $font = substr($font, 1, $length - 2);
+            }
+
+            $font = $this->expandCSSEscape($font);
+
+            // $font is a pure representation of the font name
+
+            if ($allowed_fonts !== null && !isset($allowed_fonts[$font])) {
+                continue;
+            }
+
+            if (ctype_alnum($font) && $font !== '') {
+                // very simple font, allow it in unharmed
+                $final .= $font . ', ';
+                continue;
+            }
+
+            // bugger out on whitespace.  form feed (0C) really
+            // shouldn't show up regardless
+            $font = str_replace(array("\n", "\t", "\r", "\x0C"), ' ', $font);
+
+            // Here, there are various classes of characters which need
+            // to be treated differently:
+            //  - Alphanumeric characters are essentially safe.  We
+            //    handled these above.
+            //  - Spaces require quoting, though most parsers will do
+            //    the right thing if there aren't any characters that
+            //    can be misinterpreted
+            //  - Dashes rarely occur, but they fairly unproblematic
+            //    for parsing/rendering purposes.
+            //  The above characters cover the majority of Western font
+            //  names.
+            //  - Arbitrary Unicode characters not in ASCII.  Because
+            //    most parsers give little thought to Unicode, treatment
+            //    of these codepoints is basically uniform, even for
+            //    punctuation-like codepoints.  These characters can
+            //    show up in non-Western pages and are supported by most
+            //    major browsers, for example: "MS 明朝" is a
+            //    legitimate font-name
+            //    <http://ja.wikipedia.org/wiki/MS_明朝>.  See
+            //    the CSS3 spec for more examples:
+            //    <http://www.w3.org/TR/2011/WD-css3-fonts-20110324/localizedfamilynames.png>
+            //    You can see live samples of these on the Internet:
+            //    <http://www.google.co.jp/search?q=font-family+MS+明朝|ゴシック>
+            //    However, most of these fonts have ASCII equivalents:
+            //    for example, 'MS Mincho', and it's considered
+            //    professional to use ASCII font names instead of
+            //    Unicode font names.  Thanks Takeshi Terada for
+            //    providing this information.
+            //  The following characters, to my knowledge, have not been
+            //  used to name font names.
+            //  - Single quote.  While theoretically you might find a
+            //    font name that has a single quote in its name (serving
+            //    as an apostrophe, e.g. Dave's Scribble), I haven't
+            //    been able to find any actual examples of this.
+            //    Internet Explorer's cssText translation (which I
+            //    believe is invoked by innerHTML) normalizes any
+            //    quoting to single quotes, and fails to escape single
+            //    quotes.  (Note that this is not IE's behavior for all
+            //    CSS properties, just some sort of special casing for
+            //    font-family).  So a single quote *cannot* be used
+            //    safely in the font-family context if there will be an
+            //    innerHTML/cssText translation.  Note that Firefox 3.x
+            //    does this too.
+            //  - Double quote.  In IE, these get normalized to
+            //    single-quotes, no matter what the encoding.  (Fun
+            //    fact, in IE8, the 'content' CSS property gained
+            //    support, where they special cased to preserve encoded
+            //    double quotes, but still translate unadorned double
+            //    quotes into single quotes.)  So, because their
+            //    fixpoint behavior is identical to single quotes, they
+            //    cannot be allowed either.  Firefox 3.x displays
+            //    single-quote style behavior.
+            //  - Backslashes are reduced by one (so \\ -> \) every
+            //    iteration, so they cannot be used safely.  This shows
+            //    up in IE7, IE8 and FF3
+            //  - Semicolons, commas and backticks are handled properly.
+            //  - The rest of the ASCII punctuation is handled properly.
+            // We haven't checked what browsers do to unadorned
+            // versions, but this is not important as long as the
+            // browser doesn't /remove/ surrounding quotes (as IE does
+            // for HTML).
+            //
+            // With these results in hand, we conclude that there are
+            // various levels of safety:
+            //  - Paranoid: alphanumeric, spaces and dashes(?)
+            //  - International: Paranoid + non-ASCII Unicode
+            //  - Edgy: Everything except quotes, backslashes
+            //  - NoJS: Standards compliance, e.g. sod IE. Note that
+            //    with some judicious character escaping (since certain
+            //    types of escaping doesn't work) this is theoretically
+            //    OK as long as innerHTML/cssText is not called.
+            // We believe that international is a reasonable default
+            // (that we will implement now), and once we do more
+            // extensive research, we may feel comfortable with dropping
+            // it down to edgy.
+
+            // Edgy: alphanumeric, spaces, dashes, underscores and Unicode.  Use of
+            // str(c)spn assumes that the string was already well formed
+            // Unicode (which of course it is).
+            if (strspn($font, $this->mask) !== strlen($font)) {
+                continue;
+            }
+
+            // Historical:
+            // In the absence of innerHTML/cssText, these ugly
+            // transforms don't pose a security risk (as \\ and \"
+            // might--these escapes are not supported by most browsers).
+            // We could try to be clever and use single-quote wrapping
+            // when there is a double quote present, but I have choosen
+            // not to implement that.  (NOTE: you can reduce the amount
+            // of escapes by one depending on what quoting style you use)
+            // $font = str_replace('\\', '\\5C ', $font);
+            // $font = str_replace('"',  '\\22 ', $font);
+            // $font = str_replace("'",  '\\27 ', $font);
+
+            // font possibly with spaces, requires quoting
+            $final .= "'$font', ";
+        }
+        $final = rtrim($final, ', ');
+        if ($final === '') {
+            return false;
+        }
+        return $final;
+    }
+
+}
+
+// vim: et sw=4 sts=4

+ 32 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Ident.php

@@ -0,0 +1,32 @@
+<?php
+
+/**
+ * Validates based on {ident} CSS grammar production
+ */
+class HTMLPurifier_AttrDef_CSS_Ident extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = trim($string);
+
+        // early abort: '' and '0' (strings that convert to false) are invalid
+        if (!$string) {
+            return false;
+        }
+
+        $pattern = '/^(-?[A-Za-z_][A-Za-z_\-0-9]*)$/';
+        if (!preg_match($pattern, $string)) {
+            return false;
+        }
+        return $string;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 56 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ImportantDecorator.php

@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * Decorator which enables !important to be used in CSS values.
+ */
+class HTMLPurifier_AttrDef_CSS_ImportantDecorator extends HTMLPurifier_AttrDef
+{
+    /**
+     * @type HTMLPurifier_AttrDef
+     */
+    public $def;
+    /**
+     * @type bool
+     */
+    public $allow;
+
+    /**
+     * @param HTMLPurifier_AttrDef $def Definition to wrap
+     * @param bool $allow Whether or not to allow !important
+     */
+    public function __construct($def, $allow = false)
+    {
+        $this->def = $def;
+        $this->allow = $allow;
+    }
+
+    /**
+     * Intercepts and removes !important if necessary
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        // test for ! and important tokens
+        $string = trim($string);
+        $is_important = false;
+        // :TODO: optimization: test directly for !important and ! important
+        if (strlen($string) >= 9 && substr($string, -9) === 'important') {
+            $temp = rtrim(substr($string, 0, -9));
+            // use a temp, because we might want to restore important
+            if (strlen($temp) >= 1 && substr($temp, -1) === '!') {
+                $string = rtrim(substr($temp, 0, -1));
+                $is_important = true;
+            }
+        }
+        $string = $this->def->validate($string, $config, $context);
+        if ($this->allow && $is_important) {
+            $string .= ' !important';
+        }
+        return $string;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 77 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Length.php

@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * Represents a Length as defined by CSS.
+ */
+class HTMLPurifier_AttrDef_CSS_Length extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @type HTMLPurifier_Length|string
+     */
+    protected $min;
+
+    /**
+     * @type HTMLPurifier_Length|string
+     */
+    protected $max;
+
+    /**
+     * @param HTMLPurifier_Length|string $min Minimum length, or null for no bound. String is also acceptable.
+     * @param HTMLPurifier_Length|string $max Maximum length, or null for no bound. String is also acceptable.
+     */
+    public function __construct($min = null, $max = null)
+    {
+        $this->min = $min !== null ? HTMLPurifier_Length::make($min) : null;
+        $this->max = $max !== null ? HTMLPurifier_Length::make($max) : null;
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = $this->parseCDATA($string);
+
+        // Optimizations
+        if ($string === '') {
+            return false;
+        }
+        if ($string === '0') {
+            return '0';
+        }
+        if (strlen($string) === 1) {
+            return false;
+        }
+
+        $length = HTMLPurifier_Length::make($string);
+        if (!$length->isValid()) {
+            return false;
+        }
+
+        if ($this->min) {
+            $c = $length->compareTo($this->min);
+            if ($c === false) {
+                return false;
+            }
+            if ($c < 0) {
+                return false;
+            }
+        }
+        if ($this->max) {
+            $c = $length->compareTo($this->max);
+            if ($c === false) {
+                return false;
+            }
+            if ($c > 0) {
+                return false;
+            }
+        }
+        return $length->toString();
+    }
+}
+
+// vim: et sw=4 sts=4

+ 112 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/ListStyle.php

@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * Validates shorthand CSS property list-style.
+ * @warning Does not support url tokens that have internal spaces.
+ */
+class HTMLPurifier_AttrDef_CSS_ListStyle extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * Local copy of validators.
+     * @type HTMLPurifier_AttrDef[]
+     * @note See HTMLPurifier_AttrDef_CSS_Font::$info for a similar impl.
+     */
+    protected $info;
+
+    /**
+     * @param HTMLPurifier_Config $config
+     */
+    public function __construct($config)
+    {
+        $def = $config->getCSSDefinition();
+        $this->info['list-style-type'] = $def->info['list-style-type'];
+        $this->info['list-style-position'] = $def->info['list-style-position'];
+        $this->info['list-style-image'] = $def->info['list-style-image'];
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        // regular pre-processing
+        $string = $this->parseCDATA($string);
+        if ($string === '') {
+            return false;
+        }
+
+        // assumes URI doesn't have spaces in it
+        $bits = explode(' ', strtolower($string)); // bits to process
+
+        $caught = array();
+        $caught['type'] = false;
+        $caught['position'] = false;
+        $caught['image'] = false;
+
+        $i = 0; // number of catches
+        $none = false;
+
+        foreach ($bits as $bit) {
+            if ($i >= 3) {
+                return;
+            } // optimization bit
+            if ($bit === '') {
+                continue;
+            }
+            foreach ($caught as $key => $status) {
+                if ($status !== false) {
+                    continue;
+                }
+                $r = $this->info['list-style-' . $key]->validate($bit, $config, $context);
+                if ($r === false) {
+                    continue;
+                }
+                if ($r === 'none') {
+                    if ($none) {
+                        continue;
+                    } else {
+                        $none = true;
+                    }
+                    if ($key == 'image') {
+                        continue;
+                    }
+                }
+                $caught[$key] = $r;
+                $i++;
+                break;
+            }
+        }
+
+        if (!$i) {
+            return false;
+        }
+
+        $ret = array();
+
+        // construct type
+        if ($caught['type']) {
+            $ret[] = $caught['type'];
+        }
+
+        // construct image
+        if ($caught['image']) {
+            $ret[] = $caught['image'];
+        }
+
+        // construct position
+        if ($caught['position']) {
+            $ret[] = $caught['position'];
+        }
+
+        if (empty($ret)) {
+            return false;
+        }
+        return implode(' ', $ret);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 71 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Multiple.php

@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * Framework class for strings that involve multiple values.
+ *
+ * Certain CSS properties such as border-width and margin allow multiple
+ * lengths to be specified.  This class can take a vanilla border-width
+ * definition and multiply it, usually into a max of four.
+ *
+ * @note Even though the CSS specification isn't clear about it, inherit
+ *       can only be used alone: it will never manifest as part of a multi
+ *       shorthand declaration.  Thus, this class does not allow inherit.
+ */
+class HTMLPurifier_AttrDef_CSS_Multiple extends HTMLPurifier_AttrDef
+{
+    /**
+     * Instance of component definition to defer validation to.
+     * @type HTMLPurifier_AttrDef
+     * @todo Make protected
+     */
+    public $single;
+
+    /**
+     * Max number of values allowed.
+     * @todo Make protected
+     */
+    public $max;
+
+    /**
+     * @param HTMLPurifier_AttrDef $single HTMLPurifier_AttrDef to multiply
+     * @param int $max Max number of values allowed (usually four)
+     */
+    public function __construct($single, $max = 4)
+    {
+        $this->single = $single;
+        $this->max = $max;
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = $this->mungeRgb($this->parseCDATA($string));
+        if ($string === '') {
+            return false;
+        }
+        $parts = explode(' ', $string); // parseCDATA replaced \r, \t and \n
+        $length = count($parts);
+        $final = '';
+        for ($i = 0, $num = 0; $i < $length && $num < $this->max; $i++) {
+            if (ctype_space($parts[$i])) {
+                continue;
+            }
+            $result = $this->single->validate($parts[$i], $config, $context);
+            if ($result !== false) {
+                $final .= $result . ' ';
+                $num++;
+            }
+        }
+        if ($final === '') {
+            return false;
+        }
+        return rtrim($final);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 90 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Number.php

@@ -0,0 +1,90 @@
+<?php
+
+/**
+ * Validates a number as defined by the CSS spec.
+ */
+class HTMLPurifier_AttrDef_CSS_Number extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * Indicates whether or not only positive values are allowed.
+     * @type bool
+     */
+    protected $non_negative = false;
+
+    /**
+     * @param bool $non_negative indicates whether negatives are forbidden
+     */
+    public function __construct($non_negative = false)
+    {
+        $this->non_negative = $non_negative;
+    }
+
+    /**
+     * @param string $number
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return string|bool
+     * @warning Some contexts do not pass $config, $context. These
+     *          variables should not be used without checking HTMLPurifier_Length
+     */
+    public function validate($number, $config, $context)
+    {
+        $number = $this->parseCDATA($number);
+
+        if ($number === '') {
+            return false;
+        }
+        if ($number === '0') {
+            return '0';
+        }
+
+        $sign = '';
+        switch ($number[0]) {
+            case '-':
+                if ($this->non_negative) {
+                    return false;
+                }
+                $sign = '-';
+            case '+':
+                $number = substr($number, 1);
+        }
+
+        if (ctype_digit($number)) {
+            $number = ltrim($number, '0');
+            return $number ? $sign . $number : '0';
+        }
+
+        // Period is the only non-numeric character allowed
+        if (strpos($number, '.') === false) {
+            return false;
+        }
+
+        list($left, $right) = explode('.', $number, 2);
+
+        if ($left === '' && $right === '') {
+            return false;
+        }
+        if ($left !== '' && !ctype_digit($left)) {
+            return false;
+        }
+
+        // Remove leading zeros until positive number or a zero stays left
+        if (ltrim($left, '0') != '') {
+            $left = ltrim($left, '0');
+        } else {
+            $left = '0';
+        }
+
+        $right = rtrim($right, '0');
+
+        if ($right === '') {
+            return $left ? $sign . $left : '0';
+        } elseif (!ctype_digit($right)) {
+            return false;
+        }
+        return $sign . $left . '.' . $right;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 54 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/Percentage.php

@@ -0,0 +1,54 @@
+<?php
+
+/**
+ * Validates a Percentage as defined by the CSS spec.
+ */
+class HTMLPurifier_AttrDef_CSS_Percentage extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * Instance to defer number validation to.
+     * @type HTMLPurifier_AttrDef_CSS_Number
+     */
+    protected $number_def;
+
+    /**
+     * @param bool $non_negative Whether to forbid negative values
+     */
+    public function __construct($non_negative = false)
+    {
+        $this->number_def = new HTMLPurifier_AttrDef_CSS_Number($non_negative);
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = $this->parseCDATA($string);
+
+        if ($string === '') {
+            return false;
+        }
+        $length = strlen($string);
+        if ($length === 1) {
+            return false;
+        }
+        if ($string[$length - 1] !== '%') {
+            return false;
+        }
+
+        $number = substr($string, 0, $length - 1);
+        $number = $this->number_def->validate($number, $config, $context);
+
+        if ($number === false) {
+            return false;
+        }
+        return "$number%";
+    }
+}
+
+// vim: et sw=4 sts=4

+ 46 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/TextDecoration.php

@@ -0,0 +1,46 @@
+<?php
+
+/**
+ * Validates the value for the CSS property text-decoration
+ * @note This class could be generalized into a version that acts sort of
+ *       like Enum except you can compound the allowed values.
+ */
+class HTMLPurifier_AttrDef_CSS_TextDecoration extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        static $allowed_values = array(
+            'line-through' => true,
+            'overline' => true,
+            'underline' => true,
+        );
+
+        $string = strtolower($this->parseCDATA($string));
+
+        if ($string === 'none') {
+            return $string;
+        }
+
+        $parts = explode(' ', $string);
+        $final = '';
+        foreach ($parts as $part) {
+            if (isset($allowed_values[$part])) {
+                $final .= $part . ' ';
+            }
+        }
+        $final = rtrim($final);
+        if ($final === '') {
+            return false;
+        }
+        return $final;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 77 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/CSS/URI.php

@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * Validates a URI in CSS syntax, which uses url('http://example.com')
+ * @note While theoretically speaking a URI in a CSS document could
+ *       be non-embedded, as of CSS2 there is no such usage so we're
+ *       generalizing it. This may need to be changed in the future.
+ * @warning Since HTMLPurifier_AttrDef_CSS blindly uses semicolons as
+ *          the separator, you cannot put a literal semicolon in
+ *          in the URI. Try percent encoding it, in that case.
+ */
+class HTMLPurifier_AttrDef_CSS_URI extends HTMLPurifier_AttrDef_URI
+{
+
+    public function __construct()
+    {
+        parent::__construct(true); // always embedded
+    }
+
+    /**
+     * @param string $uri_string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($uri_string, $config, $context)
+    {
+        // parse the URI out of the string and then pass it onto
+        // the parent object
+
+        $uri_string = $this->parseCDATA($uri_string);
+        if (strpos($uri_string, 'url(') !== 0) {
+            return false;
+        }
+        $uri_string = substr($uri_string, 4);
+        if (strlen($uri_string) == 0) {
+            return false;
+        }
+        $new_length = strlen($uri_string) - 1;
+        if ($uri_string[$new_length] != ')') {
+            return false;
+        }
+        $uri = trim(substr($uri_string, 0, $new_length));
+
+        if (!empty($uri) && ($uri[0] == "'" || $uri[0] == '"')) {
+            $quote = $uri[0];
+            $new_length = strlen($uri) - 1;
+            if ($uri[$new_length] !== $quote) {
+                return false;
+            }
+            $uri = substr($uri, 1, $new_length - 1);
+        }
+
+        $uri = $this->expandCSSEscape($uri);
+
+        $result = parent::validate($uri, $config, $context);
+
+        if ($result === false) {
+            return false;
+        }
+
+        // extra sanity check; should have been done by URI
+        $result = str_replace(array('"', "\\", "\n", "\x0c", "\r"), "", $result);
+
+        // suspicious characters are ()'; we're going to percent encode
+        // them for safety.
+        $result = str_replace(array('(', ')', "'"), array('%28', '%29', '%27'), $result);
+
+        // there's an extra bug where ampersands lose their escaping on
+        // an innerHTML cycle, so a very unlucky query parameter could
+        // then change the meaning of the URL.  Unfortunately, there's
+        // not much we can do about that...
+        return "url(\"$result\")";
+    }
+}
+
+// vim: et sw=4 sts=4

+ 44 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Clone.php

@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * Dummy AttrDef that mimics another AttrDef, BUT it generates clones
+ * with make.
+ */
+class HTMLPurifier_AttrDef_Clone extends HTMLPurifier_AttrDef
+{
+    /**
+     * What we're cloning.
+     * @type HTMLPurifier_AttrDef
+     */
+    protected $clone;
+
+    /**
+     * @param HTMLPurifier_AttrDef $clone
+     */
+    public function __construct($clone)
+    {
+        $this->clone = $clone;
+    }
+
+    /**
+     * @param string $v
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($v, $config, $context)
+    {
+        return $this->clone->validate($v, $config, $context);
+    }
+
+    /**
+     * @param string $string
+     * @return HTMLPurifier_AttrDef
+     */
+    public function make($string)
+    {
+        return clone $this->clone;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 73 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Enum.php

@@ -0,0 +1,73 @@
+<?php
+
+// Enum = Enumerated
+/**
+ * Validates a keyword against a list of valid values.
+ * @warning The case-insensitive compare of this function uses PHP's
+ *          built-in strtolower and ctype_lower functions, which may
+ *          cause problems with international comparisons
+ */
+class HTMLPurifier_AttrDef_Enum extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * Lookup table of valid values.
+     * @type array
+     * @todo Make protected
+     */
+    public $valid_values = array();
+
+    /**
+     * Bool indicating whether or not enumeration is case sensitive.
+     * @note In general this is always case insensitive.
+     */
+    protected $case_sensitive = false; // values according to W3C spec
+
+    /**
+     * @param array $valid_values List of valid values
+     * @param bool $case_sensitive Whether or not case sensitive
+     */
+    public function __construct($valid_values = array(), $case_sensitive = false)
+    {
+        $this->valid_values = array_flip($valid_values);
+        $this->case_sensitive = $case_sensitive;
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = trim($string);
+        if (!$this->case_sensitive) {
+            // we may want to do full case-insensitive libraries
+            $string = ctype_lower($string) ? $string : strtolower($string);
+        }
+        $result = isset($this->valid_values[$string]);
+
+        return $result ? $string : false;
+    }
+
+    /**
+     * @param string $string In form of comma-delimited list of case-insensitive
+     *      valid values. Example: "foo,bar,baz". Prepend "s:" to make
+     *      case sensitive
+     * @return HTMLPurifier_AttrDef_Enum
+     */
+    public function make($string)
+    {
+        if (strlen($string) > 2 && $string[0] == 's' && $string[1] == ':') {
+            $string = substr($string, 2);
+            $sensitive = true;
+        } else {
+            $sensitive = false;
+        }
+        $values = explode(',', $string);
+        return new HTMLPurifier_AttrDef_Enum($values, $sensitive);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 48 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Bool.php

@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * Validates a boolean attribute
+ */
+class HTMLPurifier_AttrDef_HTML_Bool extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @type string
+     */
+    protected $name;
+
+    /**
+     * @type bool
+     */
+    public $minimized = true;
+
+    /**
+     * @param bool|string $name
+     */
+    public function __construct($name = false)
+    {
+        $this->name = $name;
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        return $this->name;
+    }
+
+    /**
+     * @param string $string Name of attribute
+     * @return HTMLPurifier_AttrDef_HTML_Bool
+     */
+    public function make($string)
+    {
+        return new HTMLPurifier_AttrDef_HTML_Bool($string);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 48 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Class.php

@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * Implements special behavior for class attribute (normally NMTOKENS)
+ */
+class HTMLPurifier_AttrDef_HTML_Class extends HTMLPurifier_AttrDef_HTML_Nmtokens
+{
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    protected function split($string, $config, $context)
+    {
+        // really, this twiddle should be lazy loaded
+        $name = $config->getDefinition('HTML')->doctype->name;
+        if ($name == "XHTML 1.1" || $name == "XHTML 2.0") {
+            return parent::split($string, $config, $context);
+        } else {
+            return preg_split('/\s+/', $string);
+        }
+    }
+
+    /**
+     * @param array $tokens
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return array
+     */
+    protected function filter($tokens, $config, $context)
+    {
+        $allowed = $config->get('Attr.AllowedClasses');
+        $forbidden = $config->get('Attr.ForbiddenClasses');
+        $ret = array();
+        foreach ($tokens as $token) {
+            if (($allowed === null || isset($allowed[$token])) &&
+                !isset($forbidden[$token]) &&
+                // We need this O(n) check because of PHP's array
+                // implementation that casts -0 to 0.
+                !in_array($token, $ret, true)
+            ) {
+                $ret[] = $token;
+            }
+        }
+        return $ret;
+    }
+}

+ 51 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Color.php

@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * Validates a color according to the HTML spec.
+ */
+class HTMLPurifier_AttrDef_HTML_Color extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        static $colors = null;
+        if ($colors === null) {
+            $colors = $config->get('Core.ColorKeywords');
+        }
+
+        $string = trim($string);
+
+        if (empty($string)) {
+            return false;
+        }
+        $lower = strtolower($string);
+        if (isset($colors[$lower])) {
+            return $colors[$lower];
+        }
+        if ($string[0] === '#') {
+            $hex = substr($string, 1);
+        } else {
+            $hex = $string;
+        }
+
+        $length = strlen($hex);
+        if ($length !== 3 && $length !== 6) {
+            return false;
+        }
+        if (!ctype_xdigit($hex)) {
+            return false;
+        }
+        if ($length === 3) {
+            $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
+        }
+        return "#$hex";
+    }
+}
+
+// vim: et sw=4 sts=4

+ 38 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/FrameTarget.php

@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * Special-case enum attribute definition that lazy loads allowed frame targets
+ */
+class HTMLPurifier_AttrDef_HTML_FrameTarget extends HTMLPurifier_AttrDef_Enum
+{
+
+    /**
+     * @type array
+     */
+    public $valid_values = false; // uninitialized value
+
+    /**
+     * @type bool
+     */
+    protected $case_sensitive = false;
+
+    public function __construct()
+    {
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        if ($this->valid_values === false) {
+            $this->valid_values = $config->get('Attr.AllowedFrameTargets');
+        }
+        return parent::validate($string, $config, $context);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 113 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/ID.php

@@ -0,0 +1,113 @@
+<?php
+
+/**
+ * Validates the HTML attribute ID.
+ * @warning Even though this is the id processor, it
+ *          will ignore the directive Attr:IDBlacklist, since it will only
+ *          go according to the ID accumulator. Since the accumulator is
+ *          automatically generated, it will have already absorbed the
+ *          blacklist. If you're hacking around, make sure you use load()!
+ */
+
+class HTMLPurifier_AttrDef_HTML_ID extends HTMLPurifier_AttrDef
+{
+
+    // selector is NOT a valid thing to use for IDREFs, because IDREFs
+    // *must* target IDs that exist, whereas selector #ids do not.
+
+    /**
+     * Determines whether or not we're validating an ID in a CSS
+     * selector context.
+     * @type bool
+     */
+    protected $selector;
+
+    /**
+     * @param bool $selector
+     */
+    public function __construct($selector = false)
+    {
+        $this->selector = $selector;
+    }
+
+    /**
+     * @param string $id
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($id, $config, $context)
+    {
+        if (!$this->selector && !$config->get('Attr.EnableID')) {
+            return false;
+        }
+
+        $id = trim($id); // trim it first
+
+        if ($id === '') {
+            return false;
+        }
+
+        $prefix = $config->get('Attr.IDPrefix');
+        if ($prefix !== '') {
+            $prefix .= $config->get('Attr.IDPrefixLocal');
+            // prevent re-appending the prefix
+            if (strpos($id, $prefix) !== 0) {
+                $id = $prefix . $id;
+            }
+        } elseif ($config->get('Attr.IDPrefixLocal') !== '') {
+            trigger_error(
+                '%Attr.IDPrefixLocal cannot be used unless ' .
+                '%Attr.IDPrefix is set',
+                E_USER_WARNING
+            );
+        }
+
+        if (!$this->selector) {
+            $id_accumulator =& $context->get('IDAccumulator');
+            if (isset($id_accumulator->ids[$id])) {
+                return false;
+            }
+        }
+
+        // we purposely avoid using regex, hopefully this is faster
+
+        if ($config->get('Attr.ID.HTML5') === true) {
+            if (preg_match('/[\t\n\x0b\x0c ]/', $id)) {
+                return false;
+            }
+        } else {
+            if (ctype_alpha($id)) {
+                // OK
+            } else {
+                if (!ctype_alpha(@$id[0])) {
+                    return false;
+                }
+                // primitive style of regexps, I suppose
+                $trim = trim(
+                    $id,
+                    'A..Za..z0..9:-._'
+                );
+                if ($trim !== '') {
+                    return false;
+                }
+            }
+        }
+
+        $regexp = $config->get('Attr.IDBlacklistRegexp');
+        if ($regexp && preg_match($regexp, $id)) {
+            return false;
+        }
+
+        if (!$this->selector) {
+            $id_accumulator->add($id);
+        }
+
+        // if no change was made to the ID, return the result
+        // else, return the new id if stripping whitespace made it
+        //     valid, or return false.
+        return $id;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 56 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Length.php

@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * Validates the HTML type length (not to be confused with CSS's length).
+ *
+ * This accepts integer pixels or percentages as lengths for certain
+ * HTML attributes.
+ */
+
+class HTMLPurifier_AttrDef_HTML_Length extends HTMLPurifier_AttrDef_HTML_Pixels
+{
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = trim($string);
+        if ($string === '') {
+            return false;
+        }
+
+        $parent_result = parent::validate($string, $config, $context);
+        if ($parent_result !== false) {
+            return $parent_result;
+        }
+
+        $length = strlen($string);
+        $last_char = $string[$length - 1];
+
+        if ($last_char !== '%') {
+            return false;
+        }
+
+        $points = substr($string, 0, $length - 1);
+
+        if (!is_numeric($points)) {
+            return false;
+        }
+
+        $points = (int)$points;
+
+        if ($points < 0) {
+            return '0%';
+        }
+        if ($points > 100) {
+            return '100%';
+        }
+        return ((string)$points) . '%';
+    }
+}
+
+// vim: et sw=4 sts=4

+ 72 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/LinkTypes.php

@@ -0,0 +1,72 @@
+<?php
+
+/**
+ * Validates a rel/rev link attribute against a directive of allowed values
+ * @note We cannot use Enum because link types allow multiple
+ *       values.
+ * @note Assumes link types are ASCII text
+ */
+class HTMLPurifier_AttrDef_HTML_LinkTypes extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * Name config attribute to pull.
+     * @type string
+     */
+    protected $name;
+
+    /**
+     * @param string $name
+     */
+    public function __construct($name)
+    {
+        $configLookup = array(
+            'rel' => 'AllowedRel',
+            'rev' => 'AllowedRev'
+        );
+        if (!isset($configLookup[$name])) {
+            trigger_error(
+                'Unrecognized attribute name for link ' .
+                'relationship.',
+                E_USER_ERROR
+            );
+            return;
+        }
+        $this->name = $configLookup[$name];
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $allowed = $config->get('Attr.' . $this->name);
+        if (empty($allowed)) {
+            return false;
+        }
+
+        $string = $this->parseCDATA($string);
+        $parts = explode(' ', $string);
+
+        // lookup to prevent duplicates
+        $ret_lookup = array();
+        foreach ($parts as $part) {
+            $part = strtolower(trim($part));
+            if (!isset($allowed[$part])) {
+                continue;
+            }
+            $ret_lookup[$part] = true;
+        }
+
+        if (empty($ret_lookup)) {
+            return false;
+        }
+        $string = implode(' ', array_keys($ret_lookup));
+        return $string;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 60 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/MultiLength.php

@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * Validates a MultiLength as defined by the HTML spec.
+ *
+ * A multilength is either a integer (pixel count), a percentage, or
+ * a relative number.
+ */
+class HTMLPurifier_AttrDef_HTML_MultiLength extends HTMLPurifier_AttrDef_HTML_Length
+{
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = trim($string);
+        if ($string === '') {
+            return false;
+        }
+
+        $parent_result = parent::validate($string, $config, $context);
+        if ($parent_result !== false) {
+            return $parent_result;
+        }
+
+        $length = strlen($string);
+        $last_char = $string[$length - 1];
+
+        if ($last_char !== '*') {
+            return false;
+        }
+
+        $int = substr($string, 0, $length - 1);
+
+        if ($int == '') {
+            return '*';
+        }
+        if (!is_numeric($int)) {
+            return false;
+        }
+
+        $int = (int)$int;
+        if ($int < 0) {
+            return false;
+        }
+        if ($int == 0) {
+            return '0';
+        }
+        if ($int == 1) {
+            return '*';
+        }
+        return ((string)$int) . '*';
+    }
+}
+
+// vim: et sw=4 sts=4

+ 70 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Nmtokens.php

@@ -0,0 +1,70 @@
+<?php
+
+/**
+ * Validates contents based on NMTOKENS attribute type.
+ */
+class HTMLPurifier_AttrDef_HTML_Nmtokens extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = trim($string);
+
+        // early abort: '' and '0' (strings that convert to false) are invalid
+        if (!$string) {
+            return false;
+        }
+
+        $tokens = $this->split($string, $config, $context);
+        $tokens = $this->filter($tokens, $config, $context);
+        if (empty($tokens)) {
+            return false;
+        }
+        return implode(' ', $tokens);
+    }
+
+    /**
+     * Splits a space separated list of tokens into its constituent parts.
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return array
+     */
+    protected function split($string, $config, $context)
+    {
+        // OPTIMIZABLE!
+        // do the preg_match, capture all subpatterns for reformulation
+
+        // we don't support U+00A1 and up codepoints or
+        // escaping because I don't know how to do that with regexps
+        // and plus it would complicate optimization efforts (you never
+        // see that anyway).
+        $pattern = '/(?:(?<=\s)|\A)' . // look behind for space or string start
+            '((?:--|-?[A-Za-z_])[A-Za-z_\-0-9]*)' .
+            '(?:(?=\s)|\z)/'; // look ahead for space or string end
+        preg_match_all($pattern, $string, $matches);
+        return $matches[1];
+    }
+
+    /**
+     * Template method for removing certain tokens based on arbitrary criteria.
+     * @note If we wanted to be really functional, we'd do an array_filter
+     *       with a callback. But... we're not.
+     * @param array $tokens
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return array
+     */
+    protected function filter($tokens, $config, $context)
+    {
+        return $tokens;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 76 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/HTML/Pixels.php

@@ -0,0 +1,76 @@
+<?php
+
+/**
+ * Validates an integer representation of pixels according to the HTML spec.
+ */
+class HTMLPurifier_AttrDef_HTML_Pixels extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @type int
+     */
+    protected $max;
+
+    /**
+     * @param int $max
+     */
+    public function __construct($max = null)
+    {
+        $this->max = $max;
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = trim($string);
+        if ($string === '0') {
+            return $string;
+        }
+        if ($string === '') {
+            return false;
+        }
+        $length = strlen($string);
+        if (substr($string, $length - 2) == 'px') {
+            $string = substr($string, 0, $length - 2);
+        }
+        if (!is_numeric($string)) {
+            return false;
+        }
+        $int = (int)$string;
+
+        if ($int < 0) {
+            return '0';
+        }
+
+        // upper-bound value, extremely high values can
+        // crash operating systems, see <http://ha.ckers.org/imagecrash.html>
+        // WARNING, above link WILL crash you if you're using Windows
+
+        if ($this->max !== null && $int > $this->max) {
+            return (string)$this->max;
+        }
+        return (string)$int;
+    }
+
+    /**
+     * @param string $string
+     * @return HTMLPurifier_AttrDef
+     */
+    public function make($string)
+    {
+        if ($string === '') {
+            $max = null;
+        } else {
+            $max = (int)$string;
+        }
+        $class = get_class($this);
+        return new $class($max);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 91 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Integer.php

@@ -0,0 +1,91 @@
+<?php
+
+/**
+ * Validates an integer.
+ * @note While this class was modeled off the CSS definition, no currently
+ *       allowed CSS uses this type.  The properties that do are: widows,
+ *       orphans, z-index, counter-increment, counter-reset.  Some of the
+ *       HTML attributes, however, find use for a non-negative version of this.
+ */
+class HTMLPurifier_AttrDef_Integer extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * Whether or not negative values are allowed.
+     * @type bool
+     */
+    protected $negative = true;
+
+    /**
+     * Whether or not zero is allowed.
+     * @type bool
+     */
+    protected $zero = true;
+
+    /**
+     * Whether or not positive values are allowed.
+     * @type bool
+     */
+    protected $positive = true;
+
+    /**
+     * @param $negative Bool indicating whether or not negative values are allowed
+     * @param $zero Bool indicating whether or not zero is allowed
+     * @param $positive Bool indicating whether or not positive values are allowed
+     */
+    public function __construct($negative = true, $zero = true, $positive = true)
+    {
+        $this->negative = $negative;
+        $this->zero = $zero;
+        $this->positive = $positive;
+    }
+
+    /**
+     * @param string $integer
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($integer, $config, $context)
+    {
+        $integer = $this->parseCDATA($integer);
+        if ($integer === '') {
+            return false;
+        }
+
+        // we could possibly simply typecast it to integer, but there are
+        // certain fringe cases that must not return an integer.
+
+        // clip leading sign
+        if ($this->negative && $integer[0] === '-') {
+            $digits = substr($integer, 1);
+            if ($digits === '0') {
+                $integer = '0';
+            } // rm minus sign for zero
+        } elseif ($this->positive && $integer[0] === '+') {
+            $digits = $integer = substr($integer, 1); // rm unnecessary plus
+        } else {
+            $digits = $integer;
+        }
+
+        // test if it's numeric
+        if (!ctype_digit($digits)) {
+            return false;
+        }
+
+        // perform scope tests
+        if (!$this->zero && $integer == 0) {
+            return false;
+        }
+        if (!$this->positive && $integer > 0) {
+            return false;
+        }
+        if (!$this->negative && $integer < 0) {
+            return false;
+        }
+
+        return $integer;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 86 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Lang.php

@@ -0,0 +1,86 @@
+<?php
+
+/**
+ * Validates the HTML attribute lang, effectively a language code.
+ * @note Built according to RFC 3066, which obsoleted RFC 1766
+ */
+class HTMLPurifier_AttrDef_Lang extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $string = trim($string);
+        if (!$string) {
+            return false;
+        }
+
+        $subtags = explode('-', $string);
+        $num_subtags = count($subtags);
+
+        if ($num_subtags == 0) { // sanity check
+            return false;
+        }
+
+        // process primary subtag : $subtags[0]
+        $length = strlen($subtags[0]);
+        switch ($length) {
+            case 0:
+                return false;
+            case 1:
+                if (!($subtags[0] == 'x' || $subtags[0] == 'i')) {
+                    return false;
+                }
+                break;
+            case 2:
+            case 3:
+                if (!ctype_alpha($subtags[0])) {
+                    return false;
+                } elseif (!ctype_lower($subtags[0])) {
+                    $subtags[0] = strtolower($subtags[0]);
+                }
+                break;
+            default:
+                return false;
+        }
+
+        $new_string = $subtags[0];
+        if ($num_subtags == 1) {
+            return $new_string;
+        }
+
+        // process second subtag : $subtags[1]
+        $length = strlen($subtags[1]);
+        if ($length == 0 || ($length == 1 && $subtags[1] != 'x') || $length > 8 || !ctype_alnum($subtags[1])) {
+            return $new_string;
+        }
+        if (!ctype_lower($subtags[1])) {
+            $subtags[1] = strtolower($subtags[1]);
+        }
+
+        $new_string .= '-' . $subtags[1];
+        if ($num_subtags == 2) {
+            return $new_string;
+        }
+
+        // process all other subtags, index 2 and up
+        for ($i = 2; $i < $num_subtags; $i++) {
+            $length = strlen($subtags[$i]);
+            if ($length == 0 || $length > 8 || !ctype_alnum($subtags[$i])) {
+                return $new_string;
+            }
+            if (!ctype_lower($subtags[$i])) {
+                $subtags[$i] = strtolower($subtags[$i]);
+            }
+            $new_string .= '-' . $subtags[$i];
+        }
+        return $new_string;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 53 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Switch.php

@@ -0,0 +1,53 @@
+<?php
+
+/**
+ * Decorator that, depending on a token, switches between two definitions.
+ */
+class HTMLPurifier_AttrDef_Switch
+{
+
+    /**
+     * @type string
+     */
+    protected $tag;
+
+    /**
+     * @type HTMLPurifier_AttrDef
+     */
+    protected $withTag;
+
+    /**
+     * @type HTMLPurifier_AttrDef
+     */
+    protected $withoutTag;
+
+    /**
+     * @param string $tag Tag name to switch upon
+     * @param HTMLPurifier_AttrDef $with_tag Call if token matches tag
+     * @param HTMLPurifier_AttrDef $without_tag Call if token doesn't match, or there is no token
+     */
+    public function __construct($tag, $with_tag, $without_tag)
+    {
+        $this->tag = $tag;
+        $this->withTag = $with_tag;
+        $this->withoutTag = $without_tag;
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $token = $context->get('CurrentToken', true);
+        if (!$token || $token->name !== $this->tag) {
+            return $this->withoutTag->validate($string, $config, $context);
+        } else {
+            return $this->withTag->validate($string, $config, $context);
+        }
+    }
+}
+
+// vim: et sw=4 sts=4

+ 21 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/Text.php

@@ -0,0 +1,21 @@
+<?php
+
+/**
+ * Validates arbitrary text according to the HTML spec.
+ */
+class HTMLPurifier_AttrDef_Text extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        return $this->parseCDATA($string);
+    }
+}
+
+// vim: et sw=4 sts=4

+ 111 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI.php

@@ -0,0 +1,111 @@
+<?php
+
+/**
+ * Validates a URI as defined by RFC 3986.
+ * @note Scheme-specific mechanics deferred to HTMLPurifier_URIScheme
+ */
+class HTMLPurifier_AttrDef_URI extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * @type HTMLPurifier_URIParser
+     */
+    protected $parser;
+
+    /**
+     * @type bool
+     */
+    protected $embedsResource;
+
+    /**
+     * @param bool $embeds_resource Does the URI here result in an extra HTTP request?
+     */
+    public function __construct($embeds_resource = false)
+    {
+        $this->parser = new HTMLPurifier_URIParser();
+        $this->embedsResource = (bool)$embeds_resource;
+    }
+
+    /**
+     * @param string $string
+     * @return HTMLPurifier_AttrDef_URI
+     */
+    public function make($string)
+    {
+        $embeds = ($string === 'embedded');
+        return new HTMLPurifier_AttrDef_URI($embeds);
+    }
+
+    /**
+     * @param string $uri
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($uri, $config, $context)
+    {
+        if ($config->get('URI.Disable')) {
+            return false;
+        }
+
+        $uri = $this->parseCDATA($uri);
+
+        // parse the URI
+        $uri = $this->parser->parse($uri);
+        if ($uri === false) {
+            return false;
+        }
+
+        // add embedded flag to context for validators
+        $context->register('EmbeddedURI', $this->embedsResource);
+
+        $ok = false;
+        do {
+
+            // generic validation
+            $result = $uri->validate($config, $context);
+            if (!$result) {
+                break;
+            }
+
+            // chained filtering
+            $uri_def = $config->getDefinition('URI');
+            $result = $uri_def->filter($uri, $config, $context);
+            if (!$result) {
+                break;
+            }
+
+            // scheme-specific validation
+            $scheme_obj = $uri->getSchemeObj($config, $context);
+            if (!$scheme_obj) {
+                break;
+            }
+            if ($this->embedsResource && !$scheme_obj->browsable) {
+                break;
+            }
+            $result = $scheme_obj->validate($uri, $config, $context);
+            if (!$result) {
+                break;
+            }
+
+            // Post chained filtering
+            $result = $uri_def->postFilter($uri, $config, $context);
+            if (!$result) {
+                break;
+            }
+
+            // survived gauntlet
+            $ok = true;
+
+        } while (false);
+
+        $context->destroy('EmbeddedURI');
+        if (!$ok) {
+            return false;
+        }
+        // back to string
+        return $uri->toString();
+    }
+}
+
+// vim: et sw=4 sts=4

+ 20 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email.php

@@ -0,0 +1,20 @@
+<?php
+
+abstract class HTMLPurifier_AttrDef_URI_Email extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * Unpacks a mailbox into its display-name and address
+     * @param string $string
+     * @return mixed
+     */
+    public function unpack($string)
+    {
+        // needs to be implemented
+    }
+
+}
+
+// sub-implementations
+
+// vim: et sw=4 sts=4

+ 29 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Email/SimpleCheck.php

@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * Primitive email validation class based on the regexp found at
+ * http://www.regular-expressions.info/email.html
+ */
+class HTMLPurifier_AttrDef_URI_Email_SimpleCheck extends HTMLPurifier_AttrDef_URI_Email
+{
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        // no support for named mailboxes i.e. "Bob <bob@example.com>"
+        // that needs more percent encoding to be done
+        if ($string == '') {
+            return false;
+        }
+        $string = trim($string);
+        $result = preg_match('/^[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i', $string);
+        return $result ? $string : false;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 142 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/Host.php

@@ -0,0 +1,142 @@
+<?php
+
+/**
+ * Validates a host according to the IPv4, IPv6 and DNS (future) specifications.
+ */
+class HTMLPurifier_AttrDef_URI_Host extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * IPv4 sub-validator.
+     * @type HTMLPurifier_AttrDef_URI_IPv4
+     */
+    protected $ipv4;
+
+    /**
+     * IPv6 sub-validator.
+     * @type HTMLPurifier_AttrDef_URI_IPv6
+     */
+    protected $ipv6;
+
+    public function __construct()
+    {
+        $this->ipv4 = new HTMLPurifier_AttrDef_URI_IPv4();
+        $this->ipv6 = new HTMLPurifier_AttrDef_URI_IPv6();
+    }
+
+    /**
+     * @param string $string
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($string, $config, $context)
+    {
+        $length = strlen($string);
+        // empty hostname is OK; it's usually semantically equivalent:
+        // the default host as defined by a URI scheme is used:
+        //
+        //      If the URI scheme defines a default for host, then that
+        //      default applies when the host subcomponent is undefined
+        //      or when the registered name is empty (zero length).
+        if ($string === '') {
+            return '';
+        }
+        if ($length > 1 && $string[0] === '[' && $string[$length - 1] === ']') {
+            //IPv6
+            $ip = substr($string, 1, $length - 2);
+            $valid = $this->ipv6->validate($ip, $config, $context);
+            if ($valid === false) {
+                return false;
+            }
+            return '[' . $valid . ']';
+        }
+
+        // need to do checks on unusual encodings too
+        $ipv4 = $this->ipv4->validate($string, $config, $context);
+        if ($ipv4 !== false) {
+            return $ipv4;
+        }
+
+        // A regular domain name.
+
+        // This doesn't match I18N domain names, but we don't have proper IRI support,
+        // so force users to insert Punycode.
+
+        // There is not a good sense in which underscores should be
+        // allowed, since it's technically not! (And if you go as
+        // far to allow everything as specified by the DNS spec...
+        // well, that's literally everything, modulo some space limits
+        // for the components and the overall name (which, by the way,
+        // we are NOT checking!).  So we (arbitrarily) decide this:
+        // let's allow underscores wherever we would have allowed
+        // hyphens, if they are enabled.  This is a pretty good match
+        // for browser behavior, for example, a large number of browsers
+        // cannot handle foo_.example.com, but foo_bar.example.com is
+        // fairly well supported.
+        $underscore = $config->get('Core.AllowHostnameUnderscore') ? '_' : '';
+
+        // Based off of RFC 1738, but amended so that
+        // as per RFC 3696, the top label need only not be all numeric.
+        // The productions describing this are:
+        $a   = '[a-z]';     // alpha
+        $an  = '[a-z0-9]';  // alphanum
+        $and = "[a-z0-9-$underscore]"; // alphanum | "-"
+        // domainlabel = alphanum | alphanum *( alphanum | "-" ) alphanum
+        $domainlabel = "$an(?:$and*$an)?";
+        // AMENDED as per RFC 3696
+        // toplabel    = alphanum | alphanum *( alphanum | "-" ) alphanum
+        //      side condition: not all numeric
+        $toplabel = "$an(?:$and*$an)?";
+        // hostname    = *( domainlabel "." ) toplabel [ "." ]
+        if (preg_match("/^(?:$domainlabel\.)*($toplabel)\.?$/i", $string, $matches)) {
+            if (!ctype_digit($matches[1])) {
+                return $string;
+            }
+        }
+
+        // PHP 5.3 and later support this functionality natively
+        if (function_exists('idn_to_ascii')) {
+            if (defined('IDNA_NONTRANSITIONAL_TO_ASCII') && defined('INTL_IDNA_VARIANT_UTS46')) {
+                $string = idn_to_ascii($string, IDNA_NONTRANSITIONAL_TO_ASCII, INTL_IDNA_VARIANT_UTS46);
+            } else {
+                $string = idn_to_ascii($string);
+            }
+
+        // If we have Net_IDNA2 support, we can support IRIs by
+        // punycoding them. (This is the most portable thing to do,
+        // since otherwise we have to assume browsers support
+        } elseif ($config->get('Core.EnableIDNA')) {
+            $idna = new Net_IDNA2(array('encoding' => 'utf8', 'overlong' => false, 'strict' => true));
+            // we need to encode each period separately
+            $parts = explode('.', $string);
+            try {
+                $new_parts = array();
+                foreach ($parts as $part) {
+                    $encodable = false;
+                    for ($i = 0, $c = strlen($part); $i < $c; $i++) {
+                        if (ord($part[$i]) > 0x7a) {
+                            $encodable = true;
+                            break;
+                        }
+                    }
+                    if (!$encodable) {
+                        $new_parts[] = $part;
+                    } else {
+                        $new_parts[] = $idna->encode($part);
+                    }
+                }
+                $string = implode('.', $new_parts);
+            } catch (Exception $e) {
+                // XXX error reporting
+            }
+        }
+        // Try again
+        if (preg_match("/^($domainlabel\.)*$toplabel\.?$/i", $string)) {
+            return $string;
+        }
+        return false;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 45 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv4.php

@@ -0,0 +1,45 @@
+<?php
+
+/**
+ * Validates an IPv4 address
+ * @author Feyd @ forums.devnetwork.net (public domain)
+ */
+class HTMLPurifier_AttrDef_URI_IPv4 extends HTMLPurifier_AttrDef
+{
+
+    /**
+     * IPv4 regex, protected so that IPv6 can reuse it.
+     * @type string
+     */
+    protected $ip4;
+
+    /**
+     * @param string $aIP
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($aIP, $config, $context)
+    {
+        if (!$this->ip4) {
+            $this->_loadRegex();
+        }
+
+        if (preg_match('#^' . $this->ip4 . '$#s', $aIP)) {
+            return $aIP;
+        }
+        return false;
+    }
+
+    /**
+     * Lazy load function to prevent regex from being stuffed in
+     * cache.
+     */
+    protected function _loadRegex()
+    {
+        $oct = '(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])'; // 0-255
+        $this->ip4 = "(?:{$oct}\\.{$oct}\\.{$oct}\\.{$oct})";
+    }
+}
+
+// vim: et sw=4 sts=4

+ 89 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrDef/URI/IPv6.php

@@ -0,0 +1,89 @@
+<?php
+
+/**
+ * Validates an IPv6 address.
+ * @author Feyd @ forums.devnetwork.net (public domain)
+ * @note This function requires brackets to have been removed from address
+ *       in URI.
+ */
+class HTMLPurifier_AttrDef_URI_IPv6 extends HTMLPurifier_AttrDef_URI_IPv4
+{
+
+    /**
+     * @param string $aIP
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return bool|string
+     */
+    public function validate($aIP, $config, $context)
+    {
+        if (!$this->ip4) {
+            $this->_loadRegex();
+        }
+
+        $original = $aIP;
+
+        $hex = '[0-9a-fA-F]';
+        $blk = '(?:' . $hex . '{1,4})';
+        $pre = '(?:/(?:12[0-8]|1[0-1][0-9]|[1-9][0-9]|[0-9]))'; // /0 - /128
+
+        //      prefix check
+        if (strpos($aIP, '/') !== false) {
+            if (preg_match('#' . $pre . '$#s', $aIP, $find)) {
+                $aIP = substr($aIP, 0, 0 - strlen($find[0]));
+                unset($find);
+            } else {
+                return false;
+            }
+        }
+
+        //      IPv4-compatiblity check
+        if (preg_match('#(?<=:' . ')' . $this->ip4 . '$#s', $aIP, $find)) {
+            $aIP = substr($aIP, 0, 0 - strlen($find[0]));
+            $ip = explode('.', $find[0]);
+            $ip = array_map('dechex', $ip);
+            $aIP .= $ip[0] . $ip[1] . ':' . $ip[2] . $ip[3];
+            unset($find, $ip);
+        }
+
+        //      compression check
+        $aIP = explode('::', $aIP);
+        $c = count($aIP);
+        if ($c > 2) {
+            return false;
+        } elseif ($c == 2) {
+            list($first, $second) = $aIP;
+            $first = explode(':', $first);
+            $second = explode(':', $second);
+
+            if (count($first) + count($second) > 8) {
+                return false;
+            }
+
+            while (count($first) < 8) {
+                array_push($first, '0');
+            }
+
+            array_splice($first, 8 - count($second), 8, $second);
+            $aIP = $first;
+            unset($first, $second);
+        } else {
+            $aIP = explode(':', $aIP[0]);
+        }
+        $c = count($aIP);
+
+        if ($c != 8) {
+            return false;
+        }
+
+        //      All the pieces should be 16-bit hex strings. Are they?
+        foreach ($aIP as $piece) {
+            if (!preg_match('#^[0-9a-fA-F]{4}$#s', sprintf('%04s', $piece))) {
+                return false;
+            }
+        }
+        return $original;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 60 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform.php

@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * Processes an entire attribute array for corrections needing multiple values.
+ *
+ * Occasionally, a certain attribute will need to be removed and popped onto
+ * another value.  Instead of creating a complex return syntax for
+ * HTMLPurifier_AttrDef, we just pass the whole attribute array to a
+ * specialized object and have that do the special work.  That is the
+ * family of HTMLPurifier_AttrTransform.
+ *
+ * An attribute transformation can be assigned to run before or after
+ * HTMLPurifier_AttrDef validation.  See HTMLPurifier_HTMLDefinition for
+ * more details.
+ */
+
+abstract class HTMLPurifier_AttrTransform
+{
+
+    /**
+     * Abstract: makes changes to the attributes dependent on multiple values.
+     *
+     * @param array $attr Assoc array of attributes, usually from
+     *              HTMLPurifier_Token_Tag::$attr
+     * @param HTMLPurifier_Config $config Mandatory HTMLPurifier_Config object.
+     * @param HTMLPurifier_Context $context Mandatory HTMLPurifier_Context object
+     * @return array Processed attribute array.
+     */
+    abstract public function transform($attr, $config, $context);
+
+    /**
+     * Prepends CSS properties to the style attribute, creating the
+     * attribute if it doesn't exist.
+     * @param array &$attr Attribute array to process (passed by reference)
+     * @param string $css CSS to prepend
+     */
+    public function prependCSS(&$attr, $css)
+    {
+        $attr['style'] = isset($attr['style']) ? $attr['style'] : '';
+        $attr['style'] = $css . $attr['style'];
+    }
+
+    /**
+     * Retrieves and removes an attribute
+     * @param array &$attr Attribute array to process (passed by reference)
+     * @param mixed $key Key of attribute to confiscate
+     * @return mixed
+     */
+    public function confiscateAttr(&$attr, $key)
+    {
+        if (!isset($attr[$key])) {
+            return null;
+        }
+        $value = $attr[$key];
+        unset($attr[$key]);
+        return $value;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 28 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Background.php

@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * Pre-transform that changes proprietary background attribute to CSS.
+ */
+class HTMLPurifier_AttrTransform_Background extends HTMLPurifier_AttrTransform
+{
+    /**
+     * @param array $attr
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return array
+     */
+    public function transform($attr, $config, $context)
+    {
+        if (!isset($attr['background'])) {
+            return $attr;
+        }
+
+        $background = $this->confiscateAttr($attr, 'background');
+        // some validation should happen here
+
+        $this->prependCSS($attr, "background-image:url($background);");
+        return $attr;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 27 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BdoDir.php

@@ -0,0 +1,27 @@
+<?php
+
+// this MUST be placed in post, as it assumes that any value in dir is valid
+
+/**
+ * Post-trasnform that ensures that bdo tags have the dir attribute set.
+ */
+class HTMLPurifier_AttrTransform_BdoDir extends HTMLPurifier_AttrTransform
+{
+
+    /**
+     * @param array $attr
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return array
+     */
+    public function transform($attr, $config, $context)
+    {
+        if (isset($attr['dir'])) {
+            return $attr;
+        }
+        $attr['dir'] = $config->get('Attr.DefaultTextDir');
+        return $attr;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 28 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BgColor.php

@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * Pre-transform that changes deprecated bgcolor attribute to CSS.
+ */
+class HTMLPurifier_AttrTransform_BgColor extends HTMLPurifier_AttrTransform
+{
+    /**
+     * @param array $attr
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return array
+     */
+    public function transform($attr, $config, $context)
+    {
+        if (!isset($attr['bgcolor'])) {
+            return $attr;
+        }
+
+        $bgcolor = $this->confiscateAttr($attr, 'bgcolor');
+        // some validation should happen here
+
+        $this->prependCSS($attr, "background-color:$bgcolor;");
+        return $attr;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 47 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/BoolToCSS.php

@@ -0,0 +1,47 @@
+<?php
+
+/**
+ * Pre-transform that changes converts a boolean attribute to fixed CSS
+ */
+class HTMLPurifier_AttrTransform_BoolToCSS extends HTMLPurifier_AttrTransform
+{
+    /**
+     * Name of boolean attribute that is trigger.
+     * @type string
+     */
+    protected $attr;
+
+    /**
+     * CSS declarations to add to style, needs trailing semicolon.
+     * @type string
+     */
+    protected $css;
+
+    /**
+     * @param string $attr attribute name to convert from
+     * @param string $css CSS declarations to add to style (needs semicolon)
+     */
+    public function __construct($attr, $css)
+    {
+        $this->attr = $attr;
+        $this->css = $css;
+    }
+
+    /**
+     * @param array $attr
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return array
+     */
+    public function transform($attr, $config, $context)
+    {
+        if (!isset($attr[$this->attr])) {
+            return $attr;
+        }
+        unset($attr[$this->attr]);
+        $this->prependCSS($attr, $this->css);
+        return $attr;
+    }
+}
+
+// vim: et sw=4 sts=4

+ 26 - 0
vendor/ezyang/htmlpurifier/library/HTMLPurifier/AttrTransform/Border.php

@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * Pre-transform that changes deprecated border attribute to CSS.
+ */
+class HTMLPurifier_AttrTransform_Border extends HTMLPurifier_AttrTransform
+{
+    /**
+     * @param array $attr
+     * @param HTMLPurifier_Config $config
+     * @param HTMLPurifier_Context $context
+     * @return array
+     */
+    public function transform($attr, $config, $context)
+    {
+        if (!isset($attr['border'])) {
+            return $attr;
+        }
+        $border_width = $this->confiscateAttr($attr, 'border');
+        // some validation should happen here
+        $this->prependCSS($attr, "border:{$border_width}px solid;");
+        return $attr;
+    }
+}
+
+// vim: et sw=4 sts=4

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů